channels for concurrency; service layers with OTP API
- Currently all Video scopes are restricted, no Public URL to share to watch Videos
-
add WatchController for watching user videos added by any
-
create a view module & show template for Watch
View to provide a
player_id/1function providing Video Id doing Regex parsing for Youtube URLstemplate is mostly markup, providing Video content
-
add Route for it
get "/watch/:id", WatchController, :show -
add a Public Link to Videos listing page alongwith show; and on Show.. also make Listing page a bit leaner
-
webpackgets used to build/transform/minify JS/CSS alongwith other assets as images -
anything that doesn't need to be transformed goes into
assets/static; they plainly get copied topriv/static& served usingPlug.Staticin Endpoint -
css goes at
assets/css, js intoassets/js; 3rd party libs as jQuery goes inassets/vendor -
Phoenix makes Webpack use ES6 to provide required
importstatements -
each file is loaded in a function, not auto executed by browsers unless explicitly imported in app.js
-
although js under
assets/vendorgets auto concatenated toapp.js& executed when page loads
app.jsacts like a Manifest
- command
webpack --watchjust compiles assets into static files & copies topriv/static; the switch--watchmakes it monitor file changes
with
webpack --mode productionto do almost everything required for prod assets
- write js for Player object to handle video player details
wires up
window.onYoutubeIframeAPIReadycallback; we inject a YT iframe tag which triggers our event when player is readyimplement
onIframeReadyfunction to create player with YT iframe APIthis abstraction builds an API for video players; will let add other video supports over time
- we'll need to import Player in app.js and call
Player.initwith Video element Id if available
this completes a Publicly Watchable link to Video with embedded iframe for it, space for annotations to show and comment to be posted
-
making Videos have title friendly URL as
/<id>-<tacked-title>, add a Slug -
first
mix ecto.gen.migration add_slug_to_videosgenerating a migration file, addalter table(:videos) ..toadd :slug, :string
now
mix ecto.migrateto apply it
- Ecto allows to have separate change policy for each field; to filter/cast/validate/compose
add
field :slug, :stringto Video and pipeslugify_title/1to putsluginto non-erroneous changeset
now to fix Routes and Routing for use of Slug
- changing route call at
video#{index,show}to useslugbased route tokensto: Routes.watch_path(@conn, :show, "#{ video.id }-#{ video.slug }")
but this Routes way is not DRY as we had to concat at index, show
- customize how Phoenix generates URLs for videos; implementing protocol
Phoenix.Paramfor our custom Video type at param.ex
- the above Param implementation makes Video
showroute change which when passed towatch_path&video_pathgets similar slug just different base-pathsince this implementation could reside out of Video module, provides a cleaner polymorphism
iex(1)> v = %Videologue.Multimedia.Video{id: 1, slug: "oye"}
iex(2)> VideologueWeb.Router.Helpers.watch_path %URI{}, :show, v
"/watch/1-oye"
iex(3)> VideologueWeb.Router.Helpers.video_path %URI{}, :show, v
"/my/videos/1-oye"
iex(4)> VideologueWeb.Endpoint.struct_url() |> VideologueWeb.Router.Helpers.watch_url(:show, v)
"http://localhost:4000/watch/1-oye"
the Route gets generated but not identified, as
Repo.get!happens byidfor that
-
extend behavior to
idfields with custom type Permalink as new behavior (implementation ofEcto.Type) -
Ecto.Type behaviour expects 4 functions;
typeto return underlying type;castinvoked when values in queries are interpolated or changesets;dumpwhen persisted to db;loadwhen read from db
dump&loadhandles struct-to-db conversion
castgenerally deals with user input and hence sanitizationour works well for any string starting with a positive integer as ID should
iex(1)> Videologue.Multimedia.Permalink.cast "1"
{:ok, 1}
iex(2)> Videologue.Multimedia.Permalink.cast "1-hello"
{:ok, 1}
iex(3)> Videologue.Multimedia.Permalink.cast "1-007hello"
{:ok, 1}
- add following above
schemadef inVideologue.Multimedia.Videoto make it use custom type as primary-key id
@primary_key {:id, Videologue.Multimedia.Permalink, autogenerate: true}
the Show URLs will work now with human friendly URLs