Initial commit
This commit is contained in:
commit
e1a234e3e8
|
@ -0,0 +1,5 @@
|
||||||
|
videos
|
||||||
|
elm-stuff
|
||||||
|
js/main.js
|
||||||
|
js/main.tmp.js
|
||||||
|
js/main.min.js
|
|
@ -0,0 +1,54 @@
|
||||||
|
ifeq ("$(ELM)","")
|
||||||
|
ELM=elm
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("$(ELMLIVE)", "")
|
||||||
|
ELMLIVE=elm-live
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("$(UGLIFYJS)", "")
|
||||||
|
UGLIFYJS=uglifyjs
|
||||||
|
endif
|
||||||
|
|
||||||
|
BUILD_DIR=js
|
||||||
|
|
||||||
|
all: client-dev
|
||||||
|
release: client-release
|
||||||
|
|
||||||
|
client-dev: client/src/**
|
||||||
|
@mkdir -p $(BUILD_DIR)
|
||||||
|
$(ELM) make src/Main.elm --output $(BUILD_DIR)/main.js
|
||||||
|
|
||||||
|
client-release: client/src/**
|
||||||
|
@mkdir -p $(BUILD_DIR)
|
||||||
|
@$(ELM) make src/Main.elm --optimize --output $(BUILD_DIR)/main.tmp.js
|
||||||
|
@$(UGLIFYJS) ../$(BUILD_DIR)/main.tmp.js --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | uglifyjs --mangle > $(BUILD_DIR)/main.min.js
|
||||||
|
|
||||||
|
client-watch:
|
||||||
|
@mkdir -p $(BUILD_DIR)
|
||||||
|
@$(ELMLIVE) src/Main.elm -p 7000 -d . -- --output $(BUILD_DIR)/main.js
|
||||||
|
|
||||||
|
setup-watch:
|
||||||
|
@/bin/echo -e "\033[32;1m Watching\033[0m setup"
|
||||||
|
@cp client/src/Log.elm.debug client/src/Log.elm
|
||||||
|
@mkdir -p $(BUILD_DIR)
|
||||||
|
@cd client && $(ELMLIVE) src/Setup.elm -p 7000 -d ../$(BUILD_DIR)/ -- --output ../$(BUILD_DIR)/setup.js
|
||||||
|
|
||||||
|
server-dev:
|
||||||
|
@cd server && cargo +nightly build
|
||||||
|
|
||||||
|
server-release:
|
||||||
|
@cd server && cargo +nightly build --release
|
||||||
|
|
||||||
|
clean-client:
|
||||||
|
@/bin/echo -e "\033[32;1m Cleaning\033[0m client"
|
||||||
|
@rm -rf $(BUILD_DIR)
|
||||||
|
@/bin/echo -e "\033[32;1m Cleaned\033[0m client"
|
||||||
|
|
||||||
|
clean-server:
|
||||||
|
@/bin/echo -e "\033[32;1m Cleaning\033[0m server"
|
||||||
|
@cd server && cargo clean
|
||||||
|
@/bin/echo -e "\033[32;1m Cleaned\033[0m server"
|
||||||
|
|
||||||
|
clean: clean-client clean-server
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"type": "application",
|
||||||
|
"source-directories": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"elm-version": "0.19.1",
|
||||||
|
"dependencies": {
|
||||||
|
"direct": {
|
||||||
|
"elm/browser": "1.0.2",
|
||||||
|
"elm/core": "1.0.5",
|
||||||
|
"elm/html": "1.0.0",
|
||||||
|
"elm/http": "2.0.0",
|
||||||
|
"elm/json": "1.1.3",
|
||||||
|
"elm/url": "1.0.0",
|
||||||
|
"jims/html-parser": "1.0.0",
|
||||||
|
"mdgriffith/elm-ui": "1.1.8"
|
||||||
|
},
|
||||||
|
"indirect": {
|
||||||
|
"elm/bytes": "1.0.8",
|
||||||
|
"elm/file": "1.0.5",
|
||||||
|
"elm/parser": "1.1.0",
|
||||||
|
"elm/time": "1.0.0",
|
||||||
|
"elm/virtual-dom": "1.0.2",
|
||||||
|
"rtfeldman/elm-hex": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test-dependencies": {
|
||||||
|
"direct": {},
|
||||||
|
"indirect": {
|
||||||
|
"elm/regex": "1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!doctype HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>twitch.tforgione.fr</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container"></div>
|
||||||
|
<script src="js/main.js"></script>
|
||||||
|
<script>
|
||||||
|
Elm.Main.init({
|
||||||
|
node: document.getElementById('container')
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
module Core exposing (Model(..), Msg(..), init)
|
||||||
|
|
||||||
|
import Browser.Navigation
|
||||||
|
import Json.Decode as Decode
|
||||||
|
import Task
|
||||||
|
import Twitch
|
||||||
|
import Url
|
||||||
|
|
||||||
|
|
||||||
|
type Model
|
||||||
|
= Home
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Noop
|
||||||
|
| ReceivedPlaylists (List Twitch.Playlist)
|
||||||
|
|
||||||
|
|
||||||
|
init : Decode.Value -> Url.Url -> Browser.Navigation.Key -> ( Model, Cmd Msg )
|
||||||
|
init _ _ _ =
|
||||||
|
( Home
|
||||||
|
, Task.perform ReceivedPlaylists Twitch.fetchPlaylists
|
||||||
|
)
|
|
@ -0,0 +1,30 @@
|
||||||
|
module Main exposing (main)
|
||||||
|
|
||||||
|
import Browser
|
||||||
|
import Core
|
||||||
|
import Json.Decode as Decode
|
||||||
|
import Updates
|
||||||
|
import Url
|
||||||
|
import Views
|
||||||
|
|
||||||
|
|
||||||
|
main : Program Decode.Value Core.Model Core.Msg
|
||||||
|
main =
|
||||||
|
Browser.application
|
||||||
|
{ init = Core.init
|
||||||
|
, update = Updates.update
|
||||||
|
, view = Views.view
|
||||||
|
, subscriptions = \_ -> Sub.none
|
||||||
|
, onUrlChange = onUrlChange
|
||||||
|
, onUrlRequest = onUrlRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onUrlChange : Url.Url -> Core.Msg
|
||||||
|
onUrlChange _ =
|
||||||
|
Core.Noop
|
||||||
|
|
||||||
|
|
||||||
|
onUrlRequest : Browser.UrlRequest -> Core.Msg
|
||||||
|
onUrlRequest _ =
|
||||||
|
Core.Noop
|
|
@ -0,0 +1,135 @@
|
||||||
|
module Twitch exposing (Playlist, Video, fetchPlaylists)
|
||||||
|
|
||||||
|
import Html.Parser
|
||||||
|
import Http
|
||||||
|
import Json.Decode as Decode
|
||||||
|
import Task exposing (Task)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Playlist =
|
||||||
|
{ name : String
|
||||||
|
, videos : List Video
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Video =
|
||||||
|
{ name : String
|
||||||
|
, url : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get : { url : String, resolver : Http.Resolver x a } -> Task x a
|
||||||
|
get { url, resolver } =
|
||||||
|
Http.task
|
||||||
|
{ body = Http.emptyBody
|
||||||
|
, headers = []
|
||||||
|
, method = "GET"
|
||||||
|
, resolver = resolver
|
||||||
|
, timeout = Nothing
|
||||||
|
, url = url
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fetchPlaylists : Task x (List Playlist)
|
||||||
|
fetchPlaylists =
|
||||||
|
fetchPlaylistPath |> Task.andThen fetchPlaylistsMapper
|
||||||
|
|
||||||
|
|
||||||
|
fetchPlaylistPath : Task x (List String)
|
||||||
|
fetchPlaylistPath =
|
||||||
|
get
|
||||||
|
{ url = "/videos"
|
||||||
|
, resolver = Http.stringResolver parsePlaylistPath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fetchPlaylist : String -> Task x Playlist
|
||||||
|
fetchPlaylist name =
|
||||||
|
get
|
||||||
|
{ url = "/videos/" ++ name ++ "/description.json"
|
||||||
|
, resolver = Http.stringResolver parsePlaylist
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fetchPlaylistsMapper : List String -> Task x (List Playlist)
|
||||||
|
fetchPlaylistsMapper names =
|
||||||
|
Task.sequence (List.map fetchPlaylist names)
|
||||||
|
|
||||||
|
|
||||||
|
parsePlaylist : Http.Response String -> Result x Playlist
|
||||||
|
parsePlaylist result =
|
||||||
|
case result of
|
||||||
|
Http.GoodStatus_ _ content ->
|
||||||
|
case Decode.decodeString decodePlaylist content of
|
||||||
|
Ok p ->
|
||||||
|
Ok p
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
Ok { name = "", videos = [] }
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
Ok { name = "", videos = [] }
|
||||||
|
|
||||||
|
|
||||||
|
parsePlaylistPath : Http.Response String -> Result x (List String)
|
||||||
|
parsePlaylistPath result =
|
||||||
|
case result of
|
||||||
|
Http.GoodStatus_ _ content ->
|
||||||
|
let
|
||||||
|
withoutDoctype =
|
||||||
|
if String.startsWith "<!doctype" (String.toLower content) then
|
||||||
|
String.lines content |> List.drop 1 |> String.join "\n"
|
||||||
|
|
||||||
|
else
|
||||||
|
content
|
||||||
|
|
||||||
|
decoded =
|
||||||
|
Html.Parser.run withoutDoctype
|
||||||
|
|
||||||
|
hrefs =
|
||||||
|
Result.map findHrefs decoded
|
||||||
|
in
|
||||||
|
case hrefs of
|
||||||
|
Ok h ->
|
||||||
|
Ok h
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
Ok []
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
Ok []
|
||||||
|
|
||||||
|
|
||||||
|
findHrefsAux : List String -> Html.Parser.Node -> List String
|
||||||
|
findHrefsAux acc node =
|
||||||
|
case node of
|
||||||
|
Html.Parser.Element string (( key, value ) :: t) nodes ->
|
||||||
|
let
|
||||||
|
newAcc =
|
||||||
|
if key == "href" then
|
||||||
|
value :: acc
|
||||||
|
|
||||||
|
else
|
||||||
|
acc
|
||||||
|
in
|
||||||
|
findHrefsAux newAcc (Html.Parser.Element string t nodes)
|
||||||
|
|
||||||
|
Html.Parser.Element string [] (h :: t) ->
|
||||||
|
let
|
||||||
|
attrs =
|
||||||
|
findHrefsAux [] h
|
||||||
|
in
|
||||||
|
findHrefsAux (acc ++ attrs) (Html.Parser.Element string [] t)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
acc
|
||||||
|
|
||||||
|
|
||||||
|
findHrefs : List Html.Parser.Node -> List String
|
||||||
|
findHrefs x =
|
||||||
|
findHrefsAux [] (Html.Parser.Element "" [] x)
|
||||||
|
|
||||||
|
|
||||||
|
decodePlaylist : Decode.Decoder Playlist
|
||||||
|
decodePlaylist =
|
||||||
|
Decode.map (\x -> Playlist x []) (Decode.field "title" Decode.string)
|
|
@ -0,0 +1,17 @@
|
||||||
|
module Updates exposing (update)
|
||||||
|
|
||||||
|
import Core
|
||||||
|
|
||||||
|
|
||||||
|
update : Core.Msg -> Core.Model -> ( Core.Model, Cmd Core.Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Core.Noop ->
|
||||||
|
( model, Cmd.none )
|
||||||
|
|
||||||
|
Core.ReceivedPlaylists playlists ->
|
||||||
|
let
|
||||||
|
_ =
|
||||||
|
Debug.log "p" playlists
|
||||||
|
in
|
||||||
|
( model, Cmd.none )
|
|
@ -0,0 +1,12 @@
|
||||||
|
module Views exposing (view)
|
||||||
|
|
||||||
|
import Browser
|
||||||
|
import Core
|
||||||
|
import Element
|
||||||
|
|
||||||
|
|
||||||
|
view : Core.Model -> Browser.Document Core.Msg
|
||||||
|
view model =
|
||||||
|
{ title = "twitch.tforgione.fr"
|
||||||
|
, body = [ Element.layout [] (Element.text "sup") ]
|
||||||
|
}
|
Loading…
Reference in New Issue