Browse Source

added uspooge-app, integrated into subscriptions page

using custom version of cryogen that has rss rewritteh with data.xml.

need to make a PR or refactor it into a cryogen plugin that replaces
the default rss functionality. the new functionality is comparable to
the RSS stream produced by YT with media:group elements.
Harlan Iverson 7 năm trước cách đây
mục cha
commit
e572caad2b

+ 2 - 2
Dockerfile.streaming

@@ -5,5 +5,5 @@ FROM nginx-rtmp
 
 COPY nginx.conf /etc/nginx/nginx.conf
 
-WORKDIR /tmp/http
-ADD app/resources/public /tmp/http
+#WORKDIR /tmp/http
+#ADD app/resources/public /tmp/http

+ 1 - 1
app/project.clj

@@ -9,7 +9,7 @@
                            [compojure "1.6.0"]
                            [ring-server "0.5.0"]
                            [cryogen-markdown "0.1.7"]
-                           [cryogen-core "0.1.60"]]
+                           [cryogen-core "0.1.60-harlanji-SNAPSHOT"]]
             :plugins [[lein-ring "0.9.7"]]
             :main cryogen.core
             ;:jvm-opts ["-Xmx1G" "-Xverify:none"] ; additive by default -- https://github.com/technomancy/leiningen/pull/1230

+ 9 - 0
app/resources/templates/assets/uspooge-app/css/style.css

@@ -1,2 +1,11 @@
 /* some style */
 
+.feed-video {
+  width: 256px;
+  height: 180px;
+}
+
+.feed-item {
+  display: inline;
+  float: left;
+}

+ 7 - 1
app/resources/templates/assets/uspooge-app/index.html

@@ -11,7 +11,13 @@
       <p>Checkout your developer console.</p>
     </div>
 
-    
+<script>
+var  DEFAULT_FEED = "/video2.xml";
+
+//var  DEFAULT_FEED = "http://localhost:33936/feed.xml";
+
+
+</script>
     <script src="js/compiled/uspooge_app.js" type="text/javascript"></script>
   </body>
 </html>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 23 - 9
app/resources/templates/assets/uspooge-app/js/compiled/uspooge_app.js


+ 103 - 1
app/resources/templates/assets/uspooge-app/video.xml

@@ -1,10 +1,17 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<rss version='2.0' xmlns:atom='http://www.w3.org/2005/Atom'>
+<rss version='2.0' 
+xmlns:atom='http://www.w3.org/2005/Atom'
+xmlns:media="http://search.yahoo.com/mrss/" 
+xmlns:activity='http://activitystrea.ms/spec/1.0/'
+xmlns:yt="http://www.youtube.com/xml/schemas/2015"
+>
 <channel>
 <atom:link href='https://tinydatacenter.com/' rel='self' type='application/rss+xml'/>
+<atom:link href='https://tinydatacenter.com/' rel='alternate'/>
 <title>
 Tiny DC
 </title>
+<yt:channelId>UCUMn9G0yzhQWXiRTOmPLXOg</yt:channelId>
 <link>
 https://tinydatacenter.com/
 </link>
@@ -33,6 +40,45 @@ Token Auth
 <pubDate>
 Tue, 06 Mar 2018 00:00:00 +0000
 </pubDate>
+<activity:object-type>video</activity:object-type>
+
+
+
+
+  <yt:videoId>WvWR7m_4mdk</yt:videoId>
+
+
+
+
+  <media:group>
+   <media:title>VIDEO: RasPi Cam Test (Ocean Beach, SF)</media:title>
+   <media:content url="https://ispooge.com/embed.html?#ispooge/raspi-cam-test" type="text/html" width="960" height="540"/>
+   <media:thumbnail url="https://ispooge.com/media/videos/ispooge/raspi-cam-test.jpg" width="960" height="540"/>
+   <media:description>DESCRIPTION: VIDEO: RasPi Cam Test (Ocean Beach, SF)</media:description>
+   <media:community>
+    <media:starRating count="129" average="4.78" min="1" max="5"/>
+    <media:statistics views="5113"/>
+   </media:community>
+  </media:group>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 </item>
 <item xmlns:superlink="https://ispooge.com/schema/superlink.xsd">
 <guid>
@@ -91,6 +137,21 @@ Webserver
 <pubDate>
 Sun, 04 Feb 2018 00:00:00 +0000
 </pubDate>
+<activity:object-type>video</activity:object-type>
+
+
+  <media:group>
+   <media:title>VIDEO: Show n Tell, Mar 30</media:title>
+   <media:content url="https://ispooge.com/embed.html?#ispooge/showntell-mar3018" type="text/html" width="1280" height="720"/>
+   <media:thumbnail url="https://ispooge.com/media/videos/ispooge/showntell-mar3018.jpg" width="1280" height="720"/>
+   <media:description>DESCRIPTION: VIDEO: Show n Tell, Mar 30</media:description>
+   <media:community>
+    <media:starRating count="129" average="4.78" min="1" max="5"/>
+    <media:statistics views="5113"/>
+   </media:community>
+  </media:group>
+
+
 </item>
 <item>
 <guid>
@@ -108,6 +169,22 @@ Networked Webserver
 <pubDate>
 Sun, 04 Feb 2018 00:00:00 +0000
 </pubDate>
+
+<activity:object-type>video</activity:object-type>
+
+
+  <media:group>
+   <media:title>VIDEO: Video platforms compared</media:title>
+   <media:content url="https://ispooge.com/embed.html?#ispooge/video-platforms-compared" type="text/html" width="1280" height="720"/>
+   <media:thumbnail url="https://ispooge.com/media/videos/ispooge/video-platforms-compared.jpg" width="1280" height="720"/>
+   <media:description>DESCRIPTION: VIDEO: Video platforms compared</media:description>
+   <media:community>
+    <media:starRating count="129" average="4.78" min="1" max="5"/>
+    <media:statistics views="5113"/>
+   </media:community>
+  </media:group>
+
+
 </item>
 <item>
 <guid>
@@ -136,6 +213,31 @@ mysite.com
 <pubDate>
 Sun, 04 Feb 2018 00:00:00 +0000
 </pubDate>
+
+
+
+
+<activity:object-type>video</activity:object-type>
+
+
+
+
+
+  <media:group>
+   <media:title>VIDEO: Sunset at Ocean Beach (SF)</media:title>
+   <media:content url="https://ispooge.com/embed.html?#Random/Sunset_at_Ocean_Beach-wBA6drSk1z0" type="text/html" width="1280" height="720"/>
+   <media:thumbnail url="https://ispooge.com/media/videos/Random/Sunset_at_Ocean_Beach-wBA6drSk1z0.jpg" width="1280" height="720"/>
+   <media:description>DESCRIPTION: VIDEO: Sunset at Ocean Beach (SF)</media:description>
+   <media:community>
+    <media:starRating count="129" average="4.78" min="1" max="5"/>
+    <media:statistics views="5113"/>
+   </media:community>
+  </media:group>
+
+
+
+
+
 </item>
 <item>
 <guid>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 4 - 0
app/resources/templates/assets/uspooge-app/video2.xml


+ 4 - 0
app/resources/templates/themes/ispooge/html/subscriptions.html

@@ -19,6 +19,10 @@
   <h2>Figwheel template</h2>
   <p>Checkout your developer console.</p>
 </div>
+<script>
+var DEFAULT_FEED = "/feed.xml";
+
+</script>
 <script src="/assets/uspooge-app/js/compiled/uspooge_app.js" type="text/javascript"></script>    
     
     

+ 46 - 16
nginx.conf

@@ -2,7 +2,8 @@
 
 http {
     upstream ispooge_static {
-        server ispooge-static:9090;
+         server ispooge-static:9090;
+#        server 192.168.1.6:3000;
     }
 
     types {
@@ -14,25 +15,37 @@ http {
         listen      1936;
         listen [::]:1936 ipv6only=on;
 
-        location /hls/ {
-          rewrite  ^/hls/(.*) /$1 break;
 
-          # Disable cache
-          #add_header Cache-Control no-cache;
+        set $cors '';
+        if ($http_origin ~ '^https?\:\/\/(localhost|\d+\.\d+\.\d+.\d+|(www\.)?ispooge\.com|(www\.)?harlanji\.com|(www\.)?tinydatacenter\.com)\/?') {
+                set $cors 'C';
+        }
+
+        set $cors_opts '';
+        if ($request_method = 'OPTIONS') {
+          set $cors_opts "${cors}O";
+        }
 
-          # CORS setup
-          add_header 'Access-Control-Allow-Origin' '*' always;
-          add_header 'Access-Control-Expose-Headers' 'Content-Length';
 
-          # allow CORS preflight requests
-          if ($request_method = 'OPTIONS') {
-              add_header 'Access-Control-Allow-Origin' '*';
-              add_header 'Access-Control-Max-Age' 0;
-              add_header 'Content-Type' 'text/plain charset=UTF-8';
-              add_header 'Content-Length' 0;
-              return 204;
-          }
 
+
+        location /hls/ {
+          rewrite  ^/hls/(.*) /$1 break;
+
+          if ($cors = 'C') {
+                add_header 'Access-Control-Allow-Origin' "$http_origin" always;
+                add_header 'Access-Control-Allow-Credentials' 'true' always;
+                add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
+                add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
+                # required to be able to read Authorization header in frontend
+                #add_header 'Access-Control-Expose-Headers' 'Authorization' always;
+           }
+          if ($cors_opts = 'CO') {
+                  add_header 'Access-Control-Max-Age' 60;
+                  add_header 'Content-Type' 'text/plain charset=UTF-8';
+                  add_header 'Content-Length' 0;
+                  return 204;
+          }
           root /tmp/hls/ispooge.com/;
         }
 
@@ -46,6 +59,23 @@ http {
         }
 
         location / {
+
+
+          if ($cors = 'C') {
+                add_header 'Access-Control-Allow-Origin' "$http_origin" always;
+                add_header 'Access-Control-Allow-Credentials' 'true' always;
+                add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
+                add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
+                # required to be able to read Authorization header in frontend
+                #add_header 'Access-Control-Expose-Headers' 'Authorization' always;
+           }
+          if ($cors_opts = 'CO') {
+                  add_header 'Access-Control-Max-Age' 60;
+                  add_header 'Content-Type' 'text/plain charset=UTF-8';
+                  add_header 'Content-Length' 0;
+                  return 204;
+          }
+
           proxy_pass      http://ispooge_static/;
         }
     }

+ 2 - 2
scripts/env.sh

@@ -19,9 +19,9 @@ HOSTS=ispooge.com
 
 
 NAME_STATIC=ispooge.com-static
-IMAGE_STATIC=docker-registry.local:5000/ispooge.com/ispooge-static:25
+IMAGE_STATIC=docker-registry.local:5000/ispooge.com/ispooge-static:27
 IMAGE_STATIC_LOCAL=ispooge-static
 
 NAME_STREAMING=ispooge.com-streaming
-IMAGE_STREAMING=docker-registry.local:5000/ispooge.com/ispooge-streaming:2
+IMAGE_STREAMING=docker-registry.local:5000/ispooge.com/ispooge-streaming:3
 IMAGE_STREAMING_LOCAL=ispooge-streaming

+ 14 - 0
uspooge-app/.gitignore

@@ -0,0 +1,14 @@
+/resources/public/js/compiled/**
+figwheel_server.log
+pom.xml
+*jar
+/lib/
+/classes/
+/out/
+/target/
+.lein-deps-sum
+.lein-repl-history
+.lein-plugins/
+.repl
+.nrepl-port
+*.log

+ 39 - 0
uspooge-app/README.md

@@ -0,0 +1,39 @@
+# uspooge-app
+
+FIXME: Write a one-line description of your library/project.
+
+## Overview
+
+FIXME: Write a paragraph about the library/project and highlight its goals.
+
+## Setup
+
+To get an interactive development environment run:
+
+    lein figwheel
+
+and open your browser at [localhost:3449](http://localhost:3449/).
+This will auto compile and send all changes to the browser without the
+need to reload. After the compilation process is complete, you will
+get a Browser Connected REPL. An easy way to try it is:
+
+    (js/alert "Am I connected?")
+
+and you should see an alert in the browser window.
+
+To clean all compiled files:
+
+    lein clean
+
+To create a production build run:
+
+    lein do clean, cljsbuild once min
+
+And open your browser in `resources/public/index.html`. You will not
+get live reloading, nor a REPL. 
+
+## License
+
+Copyright © 2014 FIXME
+
+Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

+ 42 - 0
uspooge-app/dev/user.clj

@@ -0,0 +1,42 @@
+(ns user
+  (:require
+   [figwheel-sidecar.repl-api :as f]))
+
+;; user is a namespace that the Clojure runtime looks for and
+;; loads if its available
+
+;; You can place helper functions in here. This is great for starting
+;; and stopping your webserver and other development services
+
+;; The definitions in here will be available if you run "lein repl" or launch a
+;; Clojure repl some other way
+
+;; You have to ensure that the libraries you :require are listed in your dependencies
+
+;; Once you start down this path
+;; you will probably want to look at
+;; tools.namespace https://github.com/clojure/tools.namespace
+;; and Component https://github.com/stuartsierra/component
+
+
+(defn fig-start
+  "This starts the figwheel server and watch based auto-compiler."
+  []
+  ;; this call will only work are long as your :cljsbuild and
+  ;; :figwheel configurations are at the top level of your project.clj
+  ;; and are not spread across different lein profiles
+
+  ;; otherwise you can pass a configuration into start-figwheel! manually
+  (f/start-figwheel!))
+
+(defn fig-stop
+  "Stop the figwheel server and watch based auto-compiler."
+  []
+  (f/stop-figwheel!))
+
+;; if you are in an nREPL environment you will need to make sure you
+;; have setup piggieback for this to work
+(defn cljs-repl
+  "Launch a ClojureScript REPL that is connected to your build and host environment."
+  []
+  (f/cljs-repl))

+ 25 - 0
uspooge-app/package.json

@@ -0,0 +1,25 @@
+{
+  "name": "uspooge-app",
+  "version": "0.0.1",
+  "description": "",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/harlanji/uspooge-app"
+  },
+  "author": {
+    "name": "",
+    "email": ""
+  },
+  "scripts": {
+    "dev": "shadow-cljs watch app;",
+    "release": "shadow-cljs release app;",
+    "server": "shadow-cljs server;",
+    "clean": "rm -rf target; rm -rf public/js"
+  },
+  "dependencies": {
+    "create-react-class": "^15.6.2",
+    "react": "^16.2.0",
+    "react-dom": "^16.2.0",
+    "shadow-cljs": "^2.2.16"
+  }
+}

+ 119 - 0
uspooge-app/project.clj

@@ -0,0 +1,119 @@
+(defproject uspooge-app "0.1.0-SNAPSHOT"
+  :description "FIXME: write this!"
+  :url "http://example.com/FIXME"
+  :license {:name "Eclipse Public License"
+            :url "http://www.eclipse.org/legal/epl-v10.html"}
+
+  
+  
+  :min-lein-version "2.7.1"
+  :jvm-opts ["-Xmx512M"]
+
+  :dependencies [[org.clojure/clojure "1.9.0"]
+                 [org.clojure/clojurescript "1.9.946"]
+                 [org.clojure/core.async  "0.4.474"]
+                 [reagent "0.7.0"]
+                 
+                 
+
+                 [cljsjs/react-router-dom "4.2.2-0" :exclusions [cljsjs/react]]
+                 [cljs-http "0.1.44"]
+                 ]
+
+  :plugins [[lein-figwheel "0.5.15"]
+            [lein-cljsbuild "1.1.7" :exclusions [[org.clojure/clojure]]]]
+
+  :source-paths ["src"]
+
+  :cljsbuild {:builds
+              [{:id "dev"
+                :source-paths ["src"]
+
+                ;; The presence of a :figwheel configuration here
+                ;; will cause figwheel to inject the figwheel client
+                ;; into your build
+                :figwheel {:on-jsload "uspooge-app.core/on-js-reload"
+                           ;; :open-urls will pop open your application
+                           ;; in the default browser once Figwheel has
+                           ;; started and compiled your application.
+                           ;; Comment this out once it no longer serves you.
+                           :websocket-host :js-client-host
+                           :open-urls ["http://localhost:3449/index.html"]}
+
+                :compiler {:main uspooge-app.core
+                           :asset-path "js/compiled/out"
+                           :output-to "resources/public/js/compiled/uspooge_app.js"
+                           :output-dir "resources/public/js/compiled/out"
+                           :source-map-timestamp true
+                           ;; To console.log CLJS data-structures make sure you enable devtools in Chrome
+                           ;; https://github.com/binaryage/cljs-devtools
+                           :preloads [devtools.preload]}}
+
+
+               ;; This next build is a compressed minified build for
+               ;; production. You can build this with:
+               ;; lein cljsbuild once min
+               {:id "min"
+                :source-paths ["src"]
+                :compiler {:output-to "resources/public/js/compiled/uspooge_app.js"
+                           :main uspooge-app.core
+                           :optimizations :advanced
+                           :pretty-print false}}]}
+
+  :figwheel {;; :http-server-root "public" ;; default and assumes "resources"
+             ;; :server-port 3449 ;; default
+             ;; :server-ip "127.0.0.1"
+             
+             
+             :hawk-options {} ; slow but lets us work in docker/ssfhs
+
+             :css-dirs ["resources/public/css"] ;; watch and update CSS
+
+             ;; Start an nREPL server into the running figwheel process
+             ;; :nrepl-port 7888
+
+             ;; Server Ring Handler (optional)
+             ;; if you want to embed a ring handler into the figwheel http-kit
+             ;; server, this is for simple ring servers, if this
+
+             ;; doesn't work for you just run your own server :) (see lein-ring)
+
+             ;; :ring-handler hello_world.server/handler
+
+             ;; To be able to open files in your editor from the heads up display
+             ;; you will need to put a script on your path.
+             ;; that script will have to take a file path and a line number
+             ;; ie. in  ~/bin/myfile-opener
+             ;; #! /bin/sh
+             ;; emacsclient -n +$2 $1
+             ;;
+             ;; :open-file-command "myfile-opener"
+
+             ;; if you are using emacsclient you can just use
+             ;; :open-file-command "emacsclient"
+
+             ;; if you want to disable the REPL
+             ;; :repl false
+
+             ;; to configure a different figwheel logfile path
+             ;; :server-logfile "tmp/logs/figwheel-logfile.log"
+
+             ;; to pipe all the output to the repl
+             ;; :server-logfile false
+             }
+
+
+  ;; Setting up nREPL for Figwheel and ClojureScript dev
+  ;; Please see:
+  ;; https://github.com/bhauman/lein-figwheel/wiki/Using-the-Figwheel-REPL-within-NRepl
+  :profiles {:dev {:dependencies [[binaryage/devtools "0.9.9"]
+                                  [figwheel-sidecar "0.5.15"]
+                                  [com.cemerick/piggieback "0.2.2"]]
+                   ;; need to add dev source path here to get user.clj loaded
+                   :source-paths ["src" "dev"]
+                   ;; for CIDER
+                   ;; :plugins [[cider/cider-nrepl "0.12.0"]]
+                   :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}
+                   ;; need to add the compliled assets to the :clean-targets
+                   :clean-targets ^{:protect false} ["resources/public/js/compiled"
+                                                     :target-path]}})

+ 11 - 0
uspooge-app/resources/public/css/style.css

@@ -0,0 +1,11 @@
+/* some style */
+
+.feed-video {
+  width: 256px;
+  height: 180px;
+}
+
+.feed-item {
+  display: inline;
+  float: left;
+}

+ 32 - 0
uspooge-app/resources/public/index.html

@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link href="css/style.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    <div id="app">
+      <h2>Figwheel template</h2>
+      <p>Checkout your developer console.</p>
+    </div>
+
+<script>
+var  DEFAULT_FEED = "/video2.xml";
+
+//var  DEFAULT_FEED = "http://localhost:33936/feed.xml";
+
+
+</script>
+    <script src="js/compiled/uspooge_app.js" type="text/javascript"></script>
+  </body>
+</html>
+
+<!--
+<link href="/assets/uspooge-app/css/style.css" rel="stylesheet" type="text/css">
+<div id="app">
+  <h2>Figwheel template</h2>
+  <p>Checkout your developer console.</p>
+</div>
+<script src="/assets/uspooge-app/js/compiled/uspooge_app.js" type="text/javascript"></script>
+-->

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 134 - 0
uspooge-app/resources/public/video.xml


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 4 - 0
uspooge-app/resources/public/video2.xml


+ 177 - 0
uspooge-app/src/uspooge_app/core.cljs

@@ -0,0 +1,177 @@
+(ns uspooge-app.core
+    (:require-macros [cljs.core.async.macros :refer [go]])
+
+    (:require [clojure.string :as str]
+              [reagent.core :as r]
+              [cljs-http.client :as http]
+              [cljs.core.async :as async :refer [<!]]))
+
+(enable-console-print!)
+
+
+(defonce feeds (r/atom []))
+(defonce active-user (r/atom {:name "Anonymous CoW"}))
+(defonce app-state (r/atom {:text "Hello clojure world!" :__figwheel_counter 0 :active-user active-user}))
+ 
+
+
+
+
+
+
+
+(println "h      i")  
+  
+
+(defn item-is-yt? [item]
+  (not (nil? (:yt-id item))))
+
+(defn item-is-video? [item]
+  (not (nil? (:media item))))
+
+(defn video-items [items]
+  (filter #(or (item-is-video? %) (item-is-yt? %)) items))
+
+(declare video-item)
+
+(defn yt-item [item]
+  [:div {} [:iframe.feed-video {:src (str "https://www.youtube-nocookie.com/embed/" (:yt-id item) "?rel=0&amp;showinfo=0")
+                                          :frameborder "0"
+                                          :allow "autoplay; encrypted-media"
+                                          :allowfullscreen "allowfullscreen"}]])
+
+(defn feed-items [items]
+  [:ul
+    (for [item items]
+      [:li.feed-item
+        [:a {:href (:url item)} [:p (:title item)]]
+        [:div {} (if (item-is-video? item)
+          (video-item item)
+          (when (item-is-yt? item)
+            (yt-item item)))]
+      ])])
+
+
+
+(defn iframe-video-item [item]
+  (let [media (:media item)]
+    [:iframe.feed-video {:src (:url media)}]))
+
+(defn video-item [item]
+  (when (= (-> item :media :content-type) "text/html")
+    (iframe-video-item item)))
+
+(defn hello-world [app-state]
+  (fn []
+    [:div
+     [:h1 (:text @app-state)]
+     [:h2 "You are " (get @(:active-user @app-state) :name "Anonymous cow")]
+     [:h3 "Edit This and watch it change!"]
+     [:p "We've reloaded " [:strong (:__figwheel_counter @app-state)] " times (not counting errorz)."]
+     (when true
+       [:ul
+         (for [feed @feeds]
+           [:li (:title feed) (-> (:items feed) video-items feed-items)])]
+       )]))
+
+
+
+(defn on-js-reload []
+  ;; optionally touch your app-state to force rerendering depending on
+  ;; your application
+  (swap! app-state update-in [:__figwheel_counter] inc)
+
+    
+    
+)
+
+(defn ^:export login []
+ (reset! active-user {:name "Harlan TimE"}))
+
+(defn get-rss-feed [url]
+  (println "getting rss feed: " url)
+  (go (let [response (<! (http/get url
+                           {:with-credentials? false
+                            :response-type :document}))]
+    (:body response))))
+    
+
+
+
+(defn parse-media [item-node]
+  (when-let [media-group-node (.querySelector item-node "*|group")]
+    (let [content-node (.querySelector media-group-node "*|content")
+          url (.getAttribute content-node "url")
+          content-type (.getAttribute content-node "type")
+          height (.getAttribute content-node "height")
+          width (.getAttribute content-node "width")
+          media {:url url
+                 :content-type content-type
+                 :height height
+                 :width width}]
+          media)))
+
+(defn map-rss-feed-item [item-node]
+  (let [title (-> item-node (.querySelector "title") .-textContent .trim)
+        guid (-> item-node (.querySelector "guid") .-textContent .trim)
+        description (-> item-node (.querySelector "description") .-textContent .trim)
+        pub-date (new js/Date (-> item-node (.querySelector "pubDate") .-textContent .trim))
+        url (-> item-node (.querySelector "|link") .-textContent .trim)
+
+        object-type-node (.querySelector item-node "*|object-type")
+        object-type (when object-type-node (-> object-type-node .-textContent .trim))
+        
+        
+        media (parse-media item-node)
+        
+        yt-id (.querySelector item-node "*|videoId")
+        yt-id (when yt-id (-> yt-id .-textContent .trim))
+        
+        object-type (when object-type-node (-> object-type-node .-textContent .trim))
+        ]
+    {:guid guid
+     :key guid
+     :title title
+     :pub-date pub-date
+     :description description
+     :url url
+     :yt-id yt-id
+     :media media
+     :object-type object-type
+     :node item-node}))
+
+(defn map-rss-feed [feed-doc]
+  (let [title (-> feed-doc (.querySelector "title") .-textContent .trim)
+        items (map map-rss-feed-item (-> feed-doc (.querySelectorAll "item") aclone))]
+    {:title title
+     :items items
+     :doc feed-doc}))
+
+(defn get-rss-sources []
+  (let [hash (-> js/document .-location .-hash)]
+   (filter #(not (empty? %)) (str/split (.substr hash 1) ";"))))
+
+
+
+(defn ^:export add-feeds! []
+  (println "add-feeds!" js/document.location.hash)
+  (doseq [url (get-rss-sources)]
+    (go
+      (let [feed (map-rss-feed (<! (get-rss-feed url)))]
+        (swap! feeds conj feed)
+        (println "done" feed)))))
+        
+        
+
+(defn init! []
+  (r/render-component [(hello-world app-state)]
+                            (. js/document (getElementById "app")))
+  (when (= (count (get-rss-sources)) 0)
+    (set! js/document.location.hash (str "#" (or js/window.DEFAULT_FEED "/feed.xml"))))
+  (add-feeds!) 
+  nil)
+   
+  
+  
+  
+(defonce __initialized! (init!))

+ 116 - 0
uspooge-app/uSpoogeApp.bfproject

@@ -0,0 +1,116 @@
+c2e.convert_special: 0
+e2c.convert_num: 0
+openfiles: /home/hi/p/uspooge-app/src/uspooge_app/core.cljs:4484:4043:1:
+openfiles: /home/hi/p/uspooge-app/resources/public/video.xml:1384:862:0:
+openfiles: /home/hi/p/uspooge-app/project.clj:2280:2255:0:
+snr_recursion_level: 5
+convertcolumn_horizontally: 0
+adv_open_matchname: 0
+show_mbhl: 0
+fb_show_backup_f: 0
+view_line_numbers: 1
+sync_include_backup: 0
+htmlbar_thumbnailwidth: 300
+view_left_panel: 1
+bookmarks_filename_mode: 0
+e2c.convert_xml: 1
+c2e.convert_iso: 0
+opendir: file:///home/hi/p/uspooge-app
+wrap_text_default: 0
+documentroot: file:///home/hi/p/tinydatacenter/ispooge.com-v2/app/resources/public
+default_mime_type: application/x-clojure
+ssearch_text: feed-items
+snr_casesens: 0
+view_blocks: 0
+name: uSpoogeApp
+fb_show_hidden_f: 0
+editor_tab_width: 2
+show_visible_spacing: 1
+view_statusbar: 1
+display_right_margin: 1
+outputb_scroll_mode: 0
+c2e.IE_apos_workaround: 0
+enable_syntax_scan: 1
+sync_include_hidden: 0
+leftpanel_active_tab: 0
+ssearch_regex: 0
+e2c.convert_iso: 0
+ssearch_casesens: 0
+charmap_block: 1
+webroot: http://localhost:3000/
+recent_files: file:///home/hi/p/uspooge-app/resources/public/video2.xml
+recent_files: file:///home/hi/p/uspooge-app/src/uspooge_app/core.cljs
+recent_files: file:///home/hi/p/uspooge-app/project.clj
+recent_files: file:///home/hi/p/uspooge-app/resources/public/video.xml
+snr_replacetype: 0
+savedir: file:///home/hi/p/uspooge-app/src/uspooge_app
+spell_check_default: 1
+spell_insert_entities: 0
+last_filefilter: 
+htmlbar_notebooktab: 0
+view_blockstack: 1
+snr_escape_chars: 0
+fb_viewmode: 0
+c2e.convert_symbol: 0
+spell_lang: en
+ssearch_dotmatchall: 0
+searchlist: perma
+searchlist: npm
+searchlist: map-rss-f
+searchlist: polling
+searchlist: video-item
+searchlist: eed-item
+searchlist: ideo-item
+searchlist: add-feeds!
+searchlist: activity:
+searchlist: videoId
+searchlist: 25
+searchlist: 249
+searchlist: 240
+searchlist: width
+searchlist: feed-items
+autocomplete: 1
+outputb_show_all_output: 0
+bookmarks_show_mode: 0
+fb_focus_follow: 1
+snippets_show_as_menu: 0
+e2c.convert_special: 0
+autoindent: 1
+adv_open_recursive: 0
+recent_dirs: file:///home/hi/p/uspooge-app/dev
+recent_dirs: file:///home/pirate
+recent_dirs: file:///home/pirate/p
+recent_dirs: file:///home/pirate/p/uspooge-app
+recent_dirs: file:///home/pirate/p/uspooge-app/resources/public
+recent_dirs: file:///home/pirate/p/uspooge-app/src/uspooge_app
+recent_dirs: file:///home/hi
+recent_dirs: file:///home/hi/p/uspooge-app/src/uspooge_app
+recent_dirs: file:///home/hi/p/uspooge-app/resources/public
+recent_dirs: file:///home/hi/p/uspooge-app
+filegloblist: *.txt
+filegloblist: *.shtml
+filegloblist: *.py
+filegloblist: *.pl
+filegloblist: *.php
+filegloblist: *.js
+filegloblist: *.java
+filegloblist: *.htm
+filegloblist: *.html
+filegloblist: *.h
+filegloblist: *.css
+filegloblist: *.cpp
+filegloblist: *.cgi
+filegloblist: *.c
+filegloblist: *
+ssearch_unescape: 0
+htmlbar_view: 0
+c2e.convert_xml: 1
+snr_dotmatchall: 0
+sync_delete_deprecated: 0
+editor_indent_wspaces: 1
+view_cline: 1
+snr_type: 0
+snr_scope: 0
+bmarksearchmode: 0
+view_main_toolbar: 1
+e2c.convert_symbol: 0

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác