add: Task Status
This commit is contained in:
@@ -8,6 +8,8 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
#include <soci/boost-optional.h>
|
||||||
|
|
||||||
#include <ctre.hpp>
|
#include <ctre.hpp>
|
||||||
#include <fmt/chrono.h>
|
#include <fmt/chrono.h>
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
@@ -30,7 +32,9 @@ void Api::RegisterServerHandles(httplib::Server& server)
|
|||||||
|
|
||||||
server.Get("/api/files", std::bind_front(&Api::files, this));
|
server.Get("/api/files", std::bind_front(&Api::files, this));
|
||||||
|
|
||||||
server.Get("/api/file/([A-E0-9]+)", std::bind_front(&Api::file, this));
|
server.Get("/api/file/([A-F0-9]+)", std::bind_front(&Api::file, this));
|
||||||
|
|
||||||
|
server.Get("/api/status/([A-F0-9]+)", std::bind_front(&Api::status, this));
|
||||||
|
|
||||||
server.Options("/(.*)", [this](httplib::Request const& rq, httplib::Response& rp) {});
|
server.Options("/(.*)", [this](httplib::Request const& rq, httplib::Response& rp) {});
|
||||||
|
|
||||||
@@ -205,6 +209,70 @@ void Api::file(const httplib::Request& rq, httplib::Response& rs)
|
|||||||
rs.set_content("File Not Found", "text/plain");
|
rs.set_content("File Not Found", "text/plain");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Api::status(httplib::Request const& rq, httplib::Response& rs)
|
||||||
|
{
|
||||||
|
if (!rq.matches[1].matched)
|
||||||
|
{
|
||||||
|
rs.status = 404;
|
||||||
|
rs.set_content("Parameter error", "text/plain");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hash = rq.matches[1];
|
||||||
|
|
||||||
|
boost::optional<Task> data;
|
||||||
|
|
||||||
|
sql << "SELECT * FROM Tasks WHERE hash=:hash", soci::use(hash, "hash"), soci::into(data);
|
||||||
|
|
||||||
|
/*soci::rowset<Task> data = (sql.prepare << "SELECT * "
|
||||||
|
"FROM Tasks "
|
||||||
|
"WHERE hash=:hash ",
|
||||||
|
soci::use(hash, "hash"));*/
|
||||||
|
json response;
|
||||||
|
|
||||||
|
auto& status = response["status"];
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
auto const& el = data.value();
|
||||||
|
|
||||||
|
status["name"] = fmt::format("Task {}", el.hash);
|
||||||
|
status["source"] = el.url;
|
||||||
|
status["status"] = magic_enum::enum_name(el.status);
|
||||||
|
status["status_id"] = static_cast<int>(el.status);
|
||||||
|
status["timestamp"] = el.timestamp;
|
||||||
|
status["task_file_type"] =
|
||||||
|
fmt::format("{}: {}", el.audio_only ? "Audio" : "Video", el.format.value_or("Auto"));
|
||||||
|
status["id"] = el.hash;
|
||||||
|
|
||||||
|
if (el.status == FileStatus::COMPLETE)
|
||||||
|
{
|
||||||
|
boost::optional<File> file_data;
|
||||||
|
sql << "SELECT * FROM Files WHERE hash=:hash", soci::use(hash, "hash"),
|
||||||
|
soci::into(file_data);
|
||||||
|
|
||||||
|
if (file_data)
|
||||||
|
{
|
||||||
|
auto const& file = file_data.value();
|
||||||
|
|
||||||
|
auto& file_status = status["file"];
|
||||||
|
|
||||||
|
file_status["timestamp"] = file.timestamp;
|
||||||
|
file_status["name"] = file.filename;
|
||||||
|
file_status["format"] =
|
||||||
|
fmt::format("{}: {}", el.audio_only ? "Audio" : "Video", file.format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
rs.status = 404;
|
||||||
|
response["error"] = fmt::format("File '{}' not found!", hash);
|
||||||
|
}
|
||||||
|
rs.set_content(response.dump(), "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
void Api::set_cross_headers(httplib::Response& rs)
|
void Api::set_cross_headers(httplib::Response& rs)
|
||||||
{
|
{
|
||||||
rs.set_header("Access-Control-Allow-Origin", "*");
|
rs.set_header("Access-Control-Allow-Origin", "*");
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ public: // Endpoints
|
|||||||
void files(httplib::Request const& rq, httplib::Response& rs);
|
void files(httplib::Request const& rq, httplib::Response& rs);
|
||||||
void file(httplib::Request const& rq, httplib::Response& rs);
|
void file(httplib::Request const& rq, httplib::Response& rs);
|
||||||
|
|
||||||
|
void status(httplib::Request const& rq, httplib::Response& rs);
|
||||||
|
|
||||||
void set_cross_headers(httplib::Response& rs);
|
void set_cross_headers(httplib::Response& rs);
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -97,10 +97,11 @@ struct Task
|
|||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, Task const& file)
|
inline std::ostream& operator<<(std::ostream& os, Task const& file)
|
||||||
{
|
{
|
||||||
return os << fmt::format("Task [{}][{}] url: {} ",
|
return os << fmt::format("Task [{}] url: {} Audio: {} Format: {}",
|
||||||
file.id,
|
|
||||||
magic_enum::enum_name(file.status),
|
magic_enum::enum_name(file.status),
|
||||||
file.url);
|
file.url,
|
||||||
|
file.audio_only,
|
||||||
|
file.format.value_or("Auto"));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace soci
|
namespace soci
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ POST 127.0.0.1:80/api/add
|
|||||||
Content-Type: text/json
|
Content-Type: text/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"url": "https://www.youtube.com/watch?v=ZWIwLMpgcbI"
|
"url": "https://www.youtube.com/watch?v=izc1XLbU5Vk"
|
||||||
}
|
}
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
GET 127.0.0.1:80/api/queue
|
GET 127.0.0.1:80/api/files
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
GET 127.0.0.1:80/api/status/C3F953D7
|
||||||
@@ -7,8 +7,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"direct": {
|
"direct": {
|
||||||
"NoRedInk/elm-json-decode-pipeline": "1.0.0",
|
"NoRedInk/elm-json-decode-pipeline": "1.0.0",
|
||||||
|
"andrewMacmurray/elm-delay": "4.0.0",
|
||||||
"elm/browser": "1.0.2",
|
"elm/browser": "1.0.2",
|
||||||
"elm/core": "1.0.5",
|
"elm/core": "1.0.5",
|
||||||
|
"elm/file": "1.0.5",
|
||||||
"elm/html": "1.0.0",
|
"elm/html": "1.0.0",
|
||||||
"elm/http": "2.0.0",
|
"elm/http": "2.0.0",
|
||||||
"elm/json": "1.1.3",
|
"elm/json": "1.1.3",
|
||||||
@@ -17,7 +19,6 @@
|
|||||||
},
|
},
|
||||||
"indirect": {
|
"indirect": {
|
||||||
"elm/bytes": "1.0.8",
|
"elm/bytes": "1.0.8",
|
||||||
"elm/file": "1.0.5",
|
|
||||||
"elm/time": "1.0.0",
|
"elm/time": "1.0.0",
|
||||||
"elm/virtual-dom": "1.0.2"
|
"elm/virtual-dom": "1.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,15 +2,13 @@ module Files exposing (..)
|
|||||||
|
|
||||||
import Debug exposing (toString)
|
import Debug exposing (toString)
|
||||||
import Element exposing (..)
|
import Element exposing (..)
|
||||||
import Element.Background as Background
|
|
||||||
import Element.Border as Border
|
import Element.Border as Border
|
||||||
import Element.Font as Font
|
import Element.Font as Font
|
||||||
import Element.Input as Input
|
|
||||||
import Element.Region as Region
|
import Element.Region as Region
|
||||||
|
import Globals exposing (apiFiles)
|
||||||
import Http
|
import Http
|
||||||
import Json.Decode exposing (Decoder, int, list, string, succeed)
|
import Json.Decode exposing (Decoder, int, list, string, succeed)
|
||||||
import Json.Decode.Pipeline exposing (required)
|
import Json.Decode.Pipeline exposing (required)
|
||||||
import String exposing (left)
|
|
||||||
|
|
||||||
|
|
||||||
type alias File =
|
type alias File =
|
||||||
@@ -100,7 +98,7 @@ update msg model =
|
|||||||
queryFiles : Cmd Msg
|
queryFiles : Cmd Msg
|
||||||
queryFiles =
|
queryFiles =
|
||||||
Http.get
|
Http.get
|
||||||
{ url = "http://127.0.0.1/api/files"
|
{ url = apiFiles
|
||||||
, expect = Http.expectJson QueryRequestResult queueDecoder
|
, expect = Http.expectJson QueryRequestResult queueDecoder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
Modules/Website/src/Globals.elm
Normal file
21
Modules/Website/src/Globals.elm
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module Globals exposing (..)
|
||||||
|
|
||||||
|
|
||||||
|
api : String
|
||||||
|
api =
|
||||||
|
"http://127.0.0.1/api/"
|
||||||
|
|
||||||
|
|
||||||
|
apiEndpoint : String -> String
|
||||||
|
apiEndpoint path =
|
||||||
|
String.concat [ api, path ]
|
||||||
|
|
||||||
|
|
||||||
|
apiStatus : String -> String
|
||||||
|
apiStatus id = String.concat [apiEndpoint "status/", id]
|
||||||
|
|
||||||
|
apiDownloadFile : String -> String
|
||||||
|
apiDownloadFile id = String.concat [apiEndpoint "file/", id]
|
||||||
|
|
||||||
|
apiFiles : String
|
||||||
|
apiFiles = apiEndpoint "files"
|
||||||
@@ -8,7 +8,8 @@ import Element.Region as Region
|
|||||||
import Files
|
import Files
|
||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
import MainPage
|
import MainPage
|
||||||
import Route exposing (Route)
|
import Route exposing (Route(..))
|
||||||
|
import Status
|
||||||
import Url exposing (Url)
|
import Url exposing (Url)
|
||||||
|
|
||||||
|
|
||||||
@@ -23,12 +24,7 @@ type Page
|
|||||||
= NotFound
|
= NotFound
|
||||||
| Home MainPage.Model
|
| Home MainPage.Model
|
||||||
| FilesPage Files.Model
|
| FilesPage Files.Model
|
||||||
|
| StatusPage Status.Model
|
||||||
|
|
||||||
|
|
||||||
--initModel : Model
|
|
||||||
--initModel =
|
|
||||||
-- PageMain MainPage.initModel
|
|
||||||
|
|
||||||
|
|
||||||
init : () -> Url -> Nav.Key -> ( Model, Cmd Msg )
|
init : () -> Url -> Nav.Key -> ( Model, Cmd Msg )
|
||||||
@@ -64,6 +60,13 @@ initCurrentPage ( model, existingCmds ) =
|
|||||||
Files.init
|
Files.init
|
||||||
in
|
in
|
||||||
( FilesPage pageModel, Cmd.map FilesPageMsg pageCmd )
|
( FilesPage pageModel, Cmd.map FilesPageMsg pageCmd )
|
||||||
|
|
||||||
|
Route.Status file ->
|
||||||
|
let
|
||||||
|
( pageModel, pageCmd ) =
|
||||||
|
Status.init file
|
||||||
|
in
|
||||||
|
( StatusPage pageModel, Cmd.map StatusPageMsg pageCmd )
|
||||||
in
|
in
|
||||||
( { model | page = currentPage }
|
( { model | page = currentPage }
|
||||||
, Cmd.batch [ existingCmds, mappedPageCmds ]
|
, Cmd.batch [ existingCmds, mappedPageCmds ]
|
||||||
@@ -79,6 +82,7 @@ type Msg
|
|||||||
| UrlChanged Url
|
| UrlChanged Url
|
||||||
| HomePageMsg MainPage.Msg
|
| HomePageMsg MainPage.Msg
|
||||||
| FilesPageMsg Files.Msg
|
| FilesPageMsg Files.Msg
|
||||||
|
| StatusPageMsg Status.Msg
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -91,7 +95,7 @@ update msg model =
|
|||||||
( HomePageMsg subMsg, Home pageModel ) ->
|
( HomePageMsg subMsg, Home pageModel ) ->
|
||||||
let
|
let
|
||||||
( updatePageModel, updateCmd ) =
|
( updatePageModel, updateCmd ) =
|
||||||
MainPage.update subMsg pageModel
|
MainPage.update model.navKey subMsg pageModel
|
||||||
in
|
in
|
||||||
( { model | page = Home updatePageModel }
|
( { model | page = Home updatePageModel }
|
||||||
, Cmd.map HomePageMsg updateCmd
|
, Cmd.map HomePageMsg updateCmd
|
||||||
@@ -106,6 +110,15 @@ update msg model =
|
|||||||
, Cmd.map FilesPageMsg updateCmd
|
, Cmd.map FilesPageMsg updateCmd
|
||||||
)
|
)
|
||||||
|
|
||||||
|
( StatusPageMsg subMsg, StatusPage pageModel ) ->
|
||||||
|
let
|
||||||
|
( updatePageModel, updateCmd ) =
|
||||||
|
Status.update subMsg pageModel
|
||||||
|
in
|
||||||
|
( { model | page = StatusPage updatePageModel }
|
||||||
|
, Cmd.map StatusPageMsg updateCmd
|
||||||
|
)
|
||||||
|
|
||||||
( LinkClicked urlRequest, _ ) ->
|
( LinkClicked urlRequest, _ ) ->
|
||||||
case urlRequest of
|
case urlRequest of
|
||||||
Browser.Internal url ->
|
Browser.Internal url ->
|
||||||
@@ -141,6 +154,9 @@ view model =
|
|||||||
FilesPage pageModel ->
|
FilesPage pageModel ->
|
||||||
Files.view pageModel |> Element.map FilesPageMsg
|
Files.view pageModel |> Element.map FilesPageMsg
|
||||||
|
|
||||||
|
StatusPage pageModel ->
|
||||||
|
Status.view pageModel |> Element.map StatusPageMsg
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
el
|
el
|
||||||
[ Region.heading 1
|
[ Region.heading 1
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
module MainPage exposing (Model, Msg, initModel, update, view)
|
module MainPage exposing (Model, Msg, initModel, update, view)
|
||||||
|
|
||||||
|
import Browser.Navigation as Nav
|
||||||
import Color exposing (..)
|
import Color exposing (..)
|
||||||
import Element exposing (..)
|
import Element exposing (..)
|
||||||
import Element.Background as Background
|
import Element.Background as Background
|
||||||
@@ -7,13 +8,11 @@ import Element.Border as Border
|
|||||||
import Element.Font as Font
|
import Element.Font as Font
|
||||||
import Element.Input as Input
|
import Element.Input as Input
|
||||||
import Element.Region as Region
|
import Element.Region as Region
|
||||||
|
import Html exposing (form)
|
||||||
import Http
|
import Http
|
||||||
import Json.Decode exposing (Decoder, int, string, succeed)
|
import Json.Decode exposing (Decoder, int, string, succeed)
|
||||||
import Json.Decode.Pipeline exposing (required)
|
import Json.Decode.Pipeline exposing (required)
|
||||||
import Json.Encode as Encode
|
import Json.Encode as Encode
|
||||||
import List exposing (map3)
|
|
||||||
import Tuple exposing (mapBoth)
|
|
||||||
import Html exposing (form)
|
|
||||||
|
|
||||||
|
|
||||||
type alias Form =
|
type alias Form =
|
||||||
@@ -53,13 +52,21 @@ type AudioFormats
|
|||||||
| AAC
|
| AAC
|
||||||
| WAV
|
| WAV
|
||||||
|
|
||||||
|
|
||||||
audioFormatName : AudioFormats -> String
|
audioFormatName : AudioFormats -> String
|
||||||
audioFormatName format =
|
audioFormatName format =
|
||||||
case format of
|
case format of
|
||||||
MP3 -> "mp3"
|
MP3 ->
|
||||||
OPUS -> "opus"
|
"mp3"
|
||||||
AAC -> "aac"
|
|
||||||
WAV -> "wav"
|
OPUS ->
|
||||||
|
"opus"
|
||||||
|
|
||||||
|
AAC ->
|
||||||
|
"aac"
|
||||||
|
|
||||||
|
WAV ->
|
||||||
|
"wav"
|
||||||
|
|
||||||
|
|
||||||
type VideoFormats
|
type VideoFormats
|
||||||
@@ -68,38 +75,54 @@ type VideoFormats
|
|||||||
| OGG
|
| OGG
|
||||||
| WEBM
|
| WEBM
|
||||||
|
|
||||||
|
|
||||||
videoFormatName : VideoFormats -> String
|
videoFormatName : VideoFormats -> String
|
||||||
videoFormatName format =
|
videoFormatName format =
|
||||||
case format of
|
case format of
|
||||||
FLV -> "flv"
|
FLV ->
|
||||||
MP4 -> "mp4"
|
"flv"
|
||||||
OGG -> "ogg"
|
|
||||||
WEBM -> "wav"
|
MP4 ->
|
||||||
|
"mp4"
|
||||||
|
|
||||||
|
OGG ->
|
||||||
|
"ogg"
|
||||||
|
|
||||||
|
WEBM ->
|
||||||
|
"webm"
|
||||||
|
|
||||||
|
|
||||||
type Format
|
type Format
|
||||||
= Auto
|
= Auto
|
||||||
| AudioFormat AudioFormats
|
| AudioFormat AudioFormats
|
||||||
| VideoFormat VideoFormats
|
| VideoFormat VideoFormats
|
||||||
|
|
||||||
|
|
||||||
formatName : Format -> String
|
formatName : Format -> String
|
||||||
formatName format =
|
formatName format =
|
||||||
case format of
|
case format of
|
||||||
Auto -> "Auto"
|
Auto ->
|
||||||
AudioFormat audio -> audioFormatName audio
|
"Auto"
|
||||||
VideoFormat video -> videoFormatName video
|
|
||||||
|
AudioFormat audio ->
|
||||||
|
audioFormatName audio
|
||||||
|
|
||||||
|
VideoFormat video ->
|
||||||
|
videoFormatName video
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- -- Request -- --
|
-- -- Request -- --
|
||||||
|
|
||||||
|
|
||||||
type alias PostFormResponse =
|
type alias PostFormResponse =
|
||||||
{ id : Int, status : String }
|
{ id : String, status : String }
|
||||||
|
|
||||||
|
|
||||||
formDecoder : Decoder PostFormResponse
|
formDecoder : Decoder PostFormResponse
|
||||||
formDecoder =
|
formDecoder =
|
||||||
succeed PostFormResponse
|
succeed PostFormResponse
|
||||||
|> required "id" int
|
|> required "file_id" string
|
||||||
|> required "status" string
|
|> required "status" string
|
||||||
|
|
||||||
|
|
||||||
@@ -115,8 +138,9 @@ formPostEncoder form =
|
|||||||
[]
|
[]
|
||||||
, if form.format == Auto then
|
, if form.format == Auto then
|
||||||
[]
|
[]
|
||||||
else
|
|
||||||
[( "format", Encode.string <| formatName form.format )]
|
else
|
||||||
|
[ ( "format", Encode.string <| formatName form.format ) ]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -124,8 +148,8 @@ formPostEncoder form =
|
|||||||
-- -- Update -- --
|
-- -- Update -- --
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
update : Nav.Key -> Msg -> Model -> ( Model, Cmd Msg )
|
||||||
update msg model =
|
update navKey msg model =
|
||||||
case msg of
|
case msg of
|
||||||
UpdateForm new_form ->
|
UpdateForm new_form ->
|
||||||
( { model | form = new_form }, Cmd.none )
|
( { model | form = new_form }, Cmd.none )
|
||||||
@@ -151,13 +175,20 @@ update msg model =
|
|||||||
( { model | form = new_form }, Cmd.none )
|
( { model | form = new_form }, Cmd.none )
|
||||||
|
|
||||||
PostForm form ->
|
PostForm form ->
|
||||||
( model
|
if not (String.isEmpty form.url) then
|
||||||
, Http.post
|
( model
|
||||||
{ url = "http://127.0.0.1/api/add"
|
, Http.post
|
||||||
, body = Http.jsonBody (formPostEncoder form)
|
{ url = "http://127.0.0.1/api/add"
|
||||||
, expect = Http.expectJson PostResult formDecoder
|
, body = Http.jsonBody (formPostEncoder form)
|
||||||
}
|
, expect = Http.expectJson PostResult formDecoder
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
else
|
||||||
|
( model, Cmd.none )
|
||||||
|
|
||||||
|
PostResult (Ok data) ->
|
||||||
|
( model, Nav.pushUrl navKey <| String.concat [ "/status/", data.id ] )
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
( model, Cmd.none )
|
( model, Cmd.none )
|
||||||
@@ -254,6 +285,7 @@ formatButton position label state =
|
|||||||
, Border.roundEach corners
|
, Border.roundEach corners
|
||||||
, Border.widthEach borders
|
, Border.widthEach borders
|
||||||
, Border.color color.blue
|
, Border.color color.blue
|
||||||
|
, width (px 80)
|
||||||
, Background.color <|
|
, Background.color <|
|
||||||
if state == Input.Selected then
|
if state == Input.Selected then
|
||||||
color.lightBlue
|
color.lightBlue
|
||||||
@@ -269,6 +301,7 @@ formatButton position label state =
|
|||||||
formatOption format position =
|
formatOption format position =
|
||||||
Input.optionWith format <| formatButton position <| formatName format
|
Input.optionWith format <| formatButton position <| formatName format
|
||||||
|
|
||||||
|
|
||||||
view : Model -> Element Msg
|
view : Model -> Element Msg
|
||||||
view model =
|
view model =
|
||||||
Element.column
|
Element.column
|
||||||
@@ -287,15 +320,6 @@ view model =
|
|||||||
(text "localTube")
|
(text "localTube")
|
||||||
, Input.text
|
, Input.text
|
||||||
[ spacing 12
|
[ spacing 12
|
||||||
, below
|
|
||||||
(el
|
|
||||||
[ Font.color color.red
|
|
||||||
, Font.size 14
|
|
||||||
, alignRight
|
|
||||||
, moveDown 6
|
|
||||||
]
|
|
||||||
(text "This one is wrong")
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
{ text = model.form.url
|
{ text = model.form.url
|
||||||
, placeholder = Just (Input.placeholder [] (text "http://youtube.com"))
|
, placeholder = Just (Input.placeholder [] (text "http://youtube.com"))
|
||||||
@@ -325,17 +349,17 @@ view model =
|
|||||||
List.concat
|
List.concat
|
||||||
[ [ Input.optionWith Auto <| formatButton First "Auto" ]
|
[ [ Input.optionWith Auto <| formatButton First "Auto" ]
|
||||||
, if model.form.audio_only then
|
, if model.form.audio_only then
|
||||||
[ formatOption (AudioFormat MP3) Mid
|
[ formatOption (AudioFormat MP3) Mid
|
||||||
, formatOption (AudioFormat OPUS) Mid
|
, formatOption (AudioFormat OPUS) Mid
|
||||||
, formatOption (AudioFormat AAC) Mid
|
, formatOption (AudioFormat AAC) Mid
|
||||||
, formatOption (AudioFormat WAV) Last
|
, formatOption (AudioFormat WAV) Last
|
||||||
]
|
]
|
||||||
|
|
||||||
else
|
else
|
||||||
[ formatOption (VideoFormat FLV) Mid
|
[ formatOption (VideoFormat FLV) Mid
|
||||||
, formatOption (VideoFormat MP4) Mid
|
, formatOption (VideoFormat MP4) Mid
|
||||||
, formatOption (VideoFormat OGG) Mid
|
, formatOption (VideoFormat OGG) Mid
|
||||||
, formatOption (VideoFormat WEBM)Last
|
, formatOption (VideoFormat WEBM) Last
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ type Route
|
|||||||
= NotFound
|
= NotFound
|
||||||
| Home
|
| Home
|
||||||
| Files
|
| Files
|
||||||
|
| Status String
|
||||||
|
|
||||||
|
|
||||||
parseUrl : Url -> Route
|
parseUrl : Url -> Route
|
||||||
@@ -25,4 +26,5 @@ matchRoute =
|
|||||||
oneOf
|
oneOf
|
||||||
[ map Home top
|
[ map Home top
|
||||||
, map Files (s "files")
|
, map Files (s "files")
|
||||||
|
, map Status (s "status" </> string)
|
||||||
]
|
]
|
||||||
|
|||||||
232
Modules/Website/src/Status.elm
Normal file
232
Modules/Website/src/Status.elm
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
module Status exposing (Model, Msg, init, queryStatus, update, view)
|
||||||
|
|
||||||
|
import Color exposing (color)
|
||||||
|
import Debug exposing (toString)
|
||||||
|
import Delay
|
||||||
|
import Element exposing (..)
|
||||||
|
import Element.Background as Background
|
||||||
|
import Element.Border as Border
|
||||||
|
import Element.Font as Font
|
||||||
|
import Element.Input as Input
|
||||||
|
import File.Download exposing (url)
|
||||||
|
import Files exposing (Msg(..))
|
||||||
|
import Globals exposing (apiDownloadFile, apiStatus)
|
||||||
|
import Http
|
||||||
|
import Json.Decode exposing (Decoder, int, list, string, succeed)
|
||||||
|
import Json.Decode.Pipeline exposing (optional, required)
|
||||||
|
import Route exposing (Route(..))
|
||||||
|
import String exposing (right)
|
||||||
|
import Task
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Messages
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Reload
|
||||||
|
| StatusRequestResult (Result Http.Error StatusResponse)
|
||||||
|
| Download String
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Model
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ file_id : String
|
||||||
|
, status : Maybe Status
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init : String -> ( Model, Cmd Msg )
|
||||||
|
init file_id =
|
||||||
|
( { file_id = file_id, status = Nothing }, send Reload )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Request
|
||||||
|
|
||||||
|
|
||||||
|
type alias File =
|
||||||
|
{ format : String
|
||||||
|
, filename : String
|
||||||
|
, timestamp : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Status =
|
||||||
|
{ file : Maybe File
|
||||||
|
, name : String
|
||||||
|
, source : String
|
||||||
|
, status : String
|
||||||
|
, status_id : Int
|
||||||
|
, format : String
|
||||||
|
, timestamp : Int
|
||||||
|
, id : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias StatusResponse =
|
||||||
|
{ status : Status }
|
||||||
|
|
||||||
|
|
||||||
|
fileDecoder : Decoder File
|
||||||
|
fileDecoder =
|
||||||
|
succeed File
|
||||||
|
|> required "format" string
|
||||||
|
|> required "name" string
|
||||||
|
|> required "timestamp" int
|
||||||
|
|
||||||
|
|
||||||
|
statusDecoder : Decoder Status
|
||||||
|
statusDecoder =
|
||||||
|
succeed Status
|
||||||
|
|> optional "file" (Json.Decode.map Just fileDecoder) Nothing
|
||||||
|
|> required "name" string
|
||||||
|
|> required "source" string
|
||||||
|
|> required "status" string
|
||||||
|
|> required "status_id" int
|
||||||
|
|> required "task_file_type" string
|
||||||
|
|> required "timestamp" int
|
||||||
|
|> required "id" string
|
||||||
|
|
||||||
|
|
||||||
|
statusResponseDecoder : Decoder StatusResponse
|
||||||
|
statusResponseDecoder =
|
||||||
|
succeed StatusResponse
|
||||||
|
|> required "status" statusDecoder
|
||||||
|
|
||||||
|
|
||||||
|
queryStatus : String -> Cmd Msg
|
||||||
|
queryStatus id =
|
||||||
|
Http.get
|
||||||
|
{ url = apiStatus id
|
||||||
|
, expect = Http.expectJson StatusRequestResult statusResponseDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Update
|
||||||
|
|
||||||
|
|
||||||
|
cardShadow : Attr decorative msg
|
||||||
|
cardShadow =
|
||||||
|
Border.shadow
|
||||||
|
{ offset = ( 0, 4 )
|
||||||
|
, size = 4
|
||||||
|
, blur = 8
|
||||||
|
, color = rgba 0 0 0 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cardShadowOver : Attr decorative msg
|
||||||
|
cardShadowOver =
|
||||||
|
Border.shadow
|
||||||
|
{ offset = ( 0, 4 )
|
||||||
|
, size = 8
|
||||||
|
, blur = 16
|
||||||
|
, color = rgba 0 0 0 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
card : List (Attribute msg) -> Element msg -> Element msg
|
||||||
|
card attr element =
|
||||||
|
el
|
||||||
|
(List.concat
|
||||||
|
[ attr
|
||||||
|
, [ Border.rounded 15, cardShadow, mouseOver [ cardShadowOver ], padding 20 ]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
element
|
||||||
|
|
||||||
|
|
||||||
|
innerCard : List (Attribute msg) -> Element msg -> Element msg
|
||||||
|
innerCard attr element =
|
||||||
|
el
|
||||||
|
(List.concat
|
||||||
|
[ attr
|
||||||
|
, [ Border.roundEach { topLeft = 15, topRight = 15, bottomLeft = 15, bottomRight = 15 }, padding 5 ]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
element
|
||||||
|
|
||||||
|
|
||||||
|
send : msg -> Cmd msg
|
||||||
|
send msg =
|
||||||
|
Task.succeed msg
|
||||||
|
|> Task.perform identity
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Reload ->
|
||||||
|
( model, queryStatus model.file_id )
|
||||||
|
|
||||||
|
StatusRequestResult (Ok res) ->
|
||||||
|
( { model | status = Just res.status }, Delay.after 1000 Reload )
|
||||||
|
|
||||||
|
StatusRequestResult _ ->
|
||||||
|
( { model | status = Nothing }, Cmd.none )
|
||||||
|
|
||||||
|
Download file_id ->
|
||||||
|
( model, url <| apiDownloadFile file_id )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- View
|
||||||
|
--Just (Download.
|
||||||
|
|
||||||
|
|
||||||
|
statusView : Status -> Element Msg
|
||||||
|
statusView status =
|
||||||
|
card [ width fill, height shrink ]
|
||||||
|
(Element.column
|
||||||
|
[ width fill ]
|
||||||
|
[ row [ width fill, height <| px 40 ]
|
||||||
|
[ el [ Font.size 28, alignLeft ] <| text status.name
|
||||||
|
, el [ Font.size 28, alignRight ] <| text (String.concat [ "[", status.status, "]" ])
|
||||||
|
]
|
||||||
|
, link [ Font.bold, Font.underline, Font.color color.blue, Font.size 16, padding 2 ]
|
||||||
|
{ url = status.source, label = text status.source }
|
||||||
|
, el [ height <| px 10 ] none
|
||||||
|
, case status.file of
|
||||||
|
Just file ->
|
||||||
|
innerCard [ width fill, height shrink, Background.color color.grey ] <|
|
||||||
|
row [ width fill, spacing 20 ]
|
||||||
|
[ Input.button
|
||||||
|
[ Background.color color.blue
|
||||||
|
, Font.color color.white
|
||||||
|
, Border.color color.red
|
||||||
|
, paddingXY 32 16
|
||||||
|
, Border.rounded 15
|
||||||
|
]
|
||||||
|
{ onPress = Just <| Download status.id
|
||||||
|
, label = Element.text "Download"
|
||||||
|
}
|
||||||
|
, el [ Font.size 16 ] <| text file.filename
|
||||||
|
]
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
Element.none
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Element Msg
|
||||||
|
view model =
|
||||||
|
Element.column
|
||||||
|
[ width (px 800)
|
||||||
|
, height shrink
|
||||||
|
, centerX
|
||||||
|
, centerY
|
||||||
|
, spacing 36
|
||||||
|
]
|
||||||
|
[ case model.status of
|
||||||
|
Just status ->
|
||||||
|
statusView status
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
Element.text "Test"
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user