From 78037176b38e9685cdc6a1be133eba3bfa24d292 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 13:24:51 +1000 Subject: [PATCH 01/13] docs: updated README --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index f30911a..008d2d7 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,16 @@ $ go mod tidy $ bee run ``` +### cast-is +`cast-is` uses [Go Modules](https://blog.golang.org/using-go-modules) module/dependency manager, hence at least Go 1.11 is required. To ease development, [comstrek/air](https://github.com/cosmtrek/air) is used to live-reload the application. Install the tool as documented. + +To begin developing, simply enter the sub-directory and run the development server: +```shell +$ cd cast-is +$ go mod tidy +$ air +``` + ### cast-fe Populate `.env.development` with the required credentials. From 0d6d748ae51f5cf893cecce03a1bd216398f72d7 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 15:42:11 +1000 Subject: [PATCH 02/13] fix: user login prompt --- cast-fe/src/views/Scene.jsx | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/cast-fe/src/views/Scene.jsx b/cast-fe/src/views/Scene.jsx index 066442e..699f852 100644 --- a/cast-fe/src/views/Scene.jsx +++ b/cast-fe/src/views/Scene.jsx @@ -592,29 +592,37 @@ class Scene extends Component { > - Join today! + Join Today!

You need to be logged in to like, comment, chat, download, and - subscribe. By signing in, you can start sharing your own videos - and livestream too! + subscribe. Join today and you can start sharing your own videos + and stream live too!

-

Log In or Sign Up today!

- From cf4f5806e8bf75ac67a8e32be2d3849ab2d546f6 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 15:42:25 +1000 Subject: [PATCH 03/13] fix: cleaned up styling --- cast-fe/src/components/List.jsx | 2 +- cast-fe/src/components/Navigation.jsx | 46 +++++++++++++-------------- cast-fe/src/styles/index.css | 4 +-- cast-fe/src/views/Live.jsx | 2 +- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/cast-fe/src/components/List.jsx b/cast-fe/src/components/List.jsx index 9c23b52..942a15e 100644 --- a/cast-fe/src/components/List.jsx +++ b/cast-fe/src/components/List.jsx @@ -105,7 +105,7 @@ class List extends Component { {!!this.state.casts.length && this.state.finished && (
- {this.props.finishedMessage || "No more casts!"} + {this.props.finishedMessage}
)} diff --git a/cast-fe/src/components/Navigation.jsx b/cast-fe/src/components/Navigation.jsx index 84fed5f..d91929e 100644 --- a/cast-fe/src/components/Navigation.jsx +++ b/cast-fe/src/components/Navigation.jsx @@ -35,30 +35,28 @@ function Navigation() { }} /> ) : ( - <> - - + ); let searchBar = (
Live Casts From ba43238d62cf571820c545ecc766ba9e8b83a72b Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 16:10:46 +1000 Subject: [PATCH 04/13] fix: clipped title and description --- cast-fe/src/components/Cast.jsx | 4 ++++ cast-fe/src/components/CastEditable.jsx | 5 ++++- cast-fe/src/views/Scene.jsx | 6 ++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cast-fe/src/components/Cast.jsx b/cast-fe/src/components/Cast.jsx index 69f2ac5..78934e0 100644 --- a/cast-fe/src/components/Cast.jsx +++ b/cast-fe/src/components/Cast.jsx @@ -116,11 +116,15 @@ let style = { fontSize: 18, fontWeight: 600, margin: 0, + overflow: "hidden", + textOverflow: "ellipsis", }, cast_author: { fontSize: 16, fontWeight: 400, margin: 0, + overflow: "hidden", + textOverflow: "ellipsis", }, cast_duration: { fontSize: 16, diff --git a/cast-fe/src/components/CastEditable.jsx b/cast-fe/src/components/CastEditable.jsx index 227d990..583fd2f 100644 --- a/cast-fe/src/components/CastEditable.jsx +++ b/cast-fe/src/components/CastEditable.jsx @@ -408,7 +408,7 @@ class CastEditable extends Component { )} - + {this.state.error_edit && ( {this.state.error_edit} )} @@ -621,6 +621,8 @@ let style = { fontSize: "2rem", fontWeight: 600, marginBottom: 4, + overflow: "hidden", + textOverflow: "ellipsis", }, thumbnail_upload: { background: "#f0f0f088", @@ -699,6 +701,7 @@ let style = { fontSize: 16, WebkitLineClamp: "3", overflow: "hidden", + textOverflow: "ellipsis", WebkitBoxOrient: "vertical", display: "-webkit-box", }, diff --git a/cast-fe/src/views/Scene.jsx b/cast-fe/src/views/Scene.jsx index 699f852..94fbe52 100644 --- a/cast-fe/src/views/Scene.jsx +++ b/cast-fe/src/views/Scene.jsx @@ -733,6 +733,8 @@ let style = { title: { color: "#EEE", margin: 0, + overflow: "hidden", + textOverflow: "ellipsis", }, content_container: {}, spinner: { @@ -795,11 +797,11 @@ let style = { width: 128, }, description: { - // marginLeft: 48, color: "#DDD", marginTop: 16, marginBottom: 16, - // width: "80%" + overflow: "hidden", + textOverflow: "ellipsis", }, comment_input: { borderRadius: "8px 48px 8px 8px", From 1d0bc4b0d0b3993acd0297d966ed62a8d736840c Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 16:11:14 +1000 Subject: [PATCH 05/13] fix: comment error feedback --- cast-fe/src/constants/video.js | 2 ++ cast-fe/src/views/Scene.jsx | 33 +++++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/cast-fe/src/constants/video.js b/cast-fe/src/constants/video.js index cba7356..1bd1766 100644 --- a/cast-fe/src/constants/video.js +++ b/cast-fe/src/constants/video.js @@ -9,4 +9,6 @@ export const VIDEO_TAG_COUNT = 5; export const VIDEO_TAG_CHAR_LIMIT = 12; export const VIDEO_DESC_CHAR_LIMIT = 1000; +export const VIDEO_COMMENT_CHAR_LIMIT = 512; + export const VIDEO_LIST_PAGE_SIZE = 8; diff --git a/cast-fe/src/views/Scene.jsx b/cast-fe/src/views/Scene.jsx index 94fbe52..77dd572 100644 --- a/cast-fe/src/views/Scene.jsx +++ b/cast-fe/src/views/Scene.jsx @@ -24,7 +24,11 @@ import queryString from "query-string"; import Chat from "./Chat"; import MediaQuery from "react-responsive"; import { MOBILE_BP } from "../constants/breakpoint"; -import { VIDEO_TYPE_LIVE, VIDEO_TYPE_VOD } from "../constants/video"; +import { + VIDEO_COMMENT_CHAR_LIMIT, + VIDEO_TYPE_LIVE, + VIDEO_TYPE_VOD, +} from "../constants/video"; import logo from "../components/logo.svg"; import api from "../apis/api"; @@ -202,16 +206,25 @@ class Scene extends Component { error_comment: "", error_submit: "", }); + if (this.state.comment.trim().length > VIDEO_COMMENT_CHAR_LIMIT) { + this.setState({ error_comment: "Comment too long" }); + } else { + this.setState({ error_comment: "" }); + } } handleComment(e) { e.preventDefault(); if (this.state.loading.current) return; if (authManager.isAuthenticated()) { - if (!this.state.comment.trim() || this.state.error_comment) { + if (!this.state.comment.trim()) { this.setState({ error_comment: "Please enter your comment" }); return; } + if (this.state.comment.trim().length > VIDEO_COMMENT_CHAR_LIMIT) { + this.setState({ error_comment: "Comment too long" }); + return; + } if (this.state.loading.comment) return; this.setState({ loading: { ...this.state.loading, comment: true } }); this.setState({ error_submit: "" }); @@ -424,14 +437,14 @@ class Scene extends Component { style={{ marginTop: 28 }} > - + {this.state.error_submit && ( {this.state.error_submit} )} - + - + + {this.state.error_comment} + @@ -803,9 +823,6 @@ let style = { overflow: "hidden", textOverflow: "ellipsis", }, - comment_input: { - borderRadius: "8px 48px 8px 8px", - }, comment_list: { marginTop: 32, marginBottom: 16, From 5c4c9ec3be27d333ecfb2b29f09ec0268dfb72c7 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 16:36:05 +1000 Subject: [PATCH 06/13] feat: added user update guide --- cast-fe/src/styles/index.css | 2 +- cast-fe/src/views/Profile.jsx | 37 ++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/cast-fe/src/styles/index.css b/cast-fe/src/styles/index.css index 159829a..dfba017 100644 --- a/cast-fe/src/styles/index.css +++ b/cast-fe/src/styles/index.css @@ -273,7 +273,7 @@ h5, } .alert-banner { - color: hsl(7, 61%, 50%); + color: hsl(6, 79%, 52%); background-color: #9e320044; border-color: #ff4800; } diff --git a/cast-fe/src/views/Profile.jsx b/cast-fe/src/views/Profile.jsx index 982e6b1..60bb52a 100644 --- a/cast-fe/src/views/Profile.jsx +++ b/cast-fe/src/views/Profile.jsx @@ -1,10 +1,11 @@ import React, { Component } from "react"; -import { Card, Col, Container, Row } from "react-bootstrap"; +import { Alert, Button, Card, Col, Container, Row } from "react-bootstrap"; import { ProfileImage, SidebarProfile } from "../components"; import { authManager } from "../helper/auth"; import MediaQuery from "react-responsive"; import { MOBILE_BP } from "../constants/breakpoint"; import api from "../apis/api"; +import logo from "../components/logo.svg"; class Profile extends Component { constructor(props) { @@ -73,6 +74,40 @@ class Profile extends Component { + + Update Profile +

+ To update your cast user profile, you need to go to{" "} + Ratify's manage profile page and change it there. +

+

+ Once you're done, logout and log back into cast to + apply the changes. +

+
+
+ +
+

Showcase

From 80de7c6dca90d901047057e4b5debaabde12562a Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 16:37:01 +1000 Subject: [PATCH 07/13] feat: added user profile updates --- cast-be/controller/v1/auth.go | 2 +- cast-be/handlers/auth.go | 60 ++++++++++++++++++++--------------- cast-be/models/user.go | 11 +++++++ 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/cast-be/controller/v1/auth.go b/cast-be/controller/v1/auth.go index a182190..4ecdac6 100644 --- a/cast-be/controller/v1/auth.go +++ b/cast-be/controller/v1/auth.go @@ -15,7 +15,7 @@ type AuthControllerAuth struct { Handler handlers.Handler } -// @Title Register user from OID, skip if already exists +// @Title Register user from OID, skip if exists, update if required // @Param idToken body {datatransfers.UserRegister} true "registration info" // @Success 200 success // @router /check [post] diff --git a/cast-be/handlers/auth.go b/cast-be/handlers/auth.go index 523d242..775a5f6 100644 --- a/cast-be/handlers/auth.go +++ b/cast-be/handlers/auth.go @@ -20,36 +20,44 @@ func (m *module) Register(idToken datatransfers.UserRegister) (err error) { fmt.Printf("[Register] Failed parsing id_token. %+v\n", err) return } + exists := false if err = m.db.userOrm.CheckUnique("_id", user.ID); err != nil { - return nil // user exists + exists = true } - if err = m.db.userOrm.CheckUnique("username", user.Username); err != nil { - return nil // user exists + if err = m.db.userOrm.CheckUnique("username", user.Username); err != nil { // double check + exists = true } - if err = m.db.userOrm.InsertUser(user); err != nil { - fmt.Printf("[Register] Failed adding %s user entry. %+v\n", user.Username, err) - return - } - if _, err = m.db.videoOrm.InsertVideo(datatransfers.VideoInsert{ - ID: primitive.NewObjectID(), - Hash: user.Username, - Type: constants.VideoTypeLive, - Author: user.ID, - Title: fmt.Sprintf("%s's Livestream", user.Username), - Tags: []string{"live", "first"}, - Description: "Welcome to my stream!", - Resolutions: -1, - IsLive: false, - }); err != nil { - _ = m.db.userOrm.DeleteOneByID(user.ID) - fmt.Printf("[Register] Failed adding %s live video entry. %+v\n", user.Username, err) - return + if exists { + if err = m.db.userOrm.UpdateUser(user); err != nil { + fmt.Printf("[Register] Failed updating user entry. %+v\n", err) + return + } + } else { + if err = m.db.userOrm.InsertUser(user); err != nil { + fmt.Printf("[Register] Failed adding %s user entry. %+v\n", user.Username, err) + return + } + if _, err = m.db.videoOrm.InsertVideo(datatransfers.VideoInsert{ + ID: primitive.NewObjectID(), + Hash: user.Username, + Type: constants.VideoTypeLive, + Author: user.ID, + Title: fmt.Sprintf("%s's Livestream", user.Username), + Tags: []string{"live", "first"}, + Description: "Welcome to my stream!", + Resolutions: -1, + IsLive: false, + }); err != nil { + _ = m.db.userOrm.DeleteOneByID(user.ID) + fmt.Printf("[Register] Failed adding %s live video entry. %+v\n", user.Username, err) + return + } + _, _ = m.s3.CopyObject(&s3.CopyObjectInput{ + Bucket: aws.String(config.AppConfig.S3Bucket), + CopySource: aws.String(fmt.Sprintf("%s/%s.jpg", config.AppConfig.S3Bucket, constants.ThumbnailDefault)), + Key: aws.String(fmt.Sprintf("%s/%s.jpg", constants.ThumbnailRootDir, user.Username)), + }) } - _, _ = m.s3.CopyObject(&s3.CopyObjectInput{ - Bucket: aws.String(config.AppConfig.S3Bucket), - CopySource: aws.String(fmt.Sprintf("%s/%s.jpg", config.AppConfig.S3Bucket, constants.ThumbnailDefault)), - Key: aws.String(fmt.Sprintf("%s/%s.jpg", constants.ThumbnailRootDir, user.Username)), - }) return } diff --git a/cast-be/models/user.go b/cast-be/models/user.go index 5b0f766..e1b10d1 100644 --- a/cast-be/models/user.go +++ b/cast-be/models/user.go @@ -18,6 +18,7 @@ type UserOrmer interface { GetOneByUsername(username string) (user datatransfers.User, err error) CheckUnique(field, value string) (err error) InsertUser(user datatransfers.User) (err error) + UpdateUser(user datatransfers.User) (err error) DeleteOneByID(ID string) (err error) } @@ -55,6 +56,16 @@ func (o *userOrm) InsertUser(user datatransfers.User) (err error) { return } +func (o *userOrm) UpdateUser(user datatransfers.User) (err error) { + return o.collection.FindOneAndUpdate(context.Background(), + bson.M{"_id": user.ID}, + bson.D{{"$set", bson.D{ + {"username", user.Username}, + {"name", user.Name}, + }}}, + ).Err() +} + func (o *userOrm) DeleteOneByID(ID string) (err error) { _, err = o.collection.DeleteOne(context.Background(), bson.M{"_id": ID}) return From c1c64eb641e676b9f7b7ee1c1a50e7f2b878281f Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 17:04:54 +1000 Subject: [PATCH 08/13] chore: cleaned up deps and imports --- cast-fe/package.json | 6 +----- cast-fe/src/views/Profile.jsx | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/cast-fe/package.json b/cast-fe/package.json index 7e4bc98..b0594c1 100644 --- a/cast-fe/package.json +++ b/cast-fe/package.json @@ -9,7 +9,6 @@ "bs-custom-file-input": "^1.3.4", "dashjs": "^3.0.3", "flv.js": "^1.5.0", - "js-cookie": "^2.2.1", "query-string": "^6.12.1", "react": "^16.13.0", "react-bootstrap": "^1.0.0-beta.17", @@ -22,17 +21,14 @@ "react-responsive": "^8.0.3", "react-router-dom": "^5.1.2", "react-scripts": "3.4.0", - "react-scroll": "^1.7.16", "react-tag-input": "^6.4.2", "react-timeago": "^4.4.0", "react-toastify": "^6.0.4", - "react-truncate": "^2.4.0", "video.js": "^7.6.6", "videojs-contrib-dash": "^2.11.0", "videojs-contrib-quality-levels": "^2.0.9", "videojs-flvjs-es6": "^1.0.1", - "videojs-http-source-selector": "^1.1.6", - "zxcvbn": "^4.4.2" + "videojs-http-source-selector": "^1.1.6" }, "scripts": { "start": "react-scripts start", diff --git a/cast-fe/src/views/Profile.jsx b/cast-fe/src/views/Profile.jsx index 60bb52a..a798a50 100644 --- a/cast-fe/src/views/Profile.jsx +++ b/cast-fe/src/views/Profile.jsx @@ -5,7 +5,6 @@ import { authManager } from "../helper/auth"; import MediaQuery from "react-responsive"; import { MOBILE_BP } from "../constants/breakpoint"; import api from "../apis/api"; -import logo from "../components/logo.svg"; class Profile extends Component { constructor(props) { From dde341e6e7c9ec34c50d033dbdc84711cd41d7d5 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 17:38:37 +1000 Subject: [PATCH 09/13] feat: added unlisted video flag --- cast-be/controller/v1/video.go | 2 ++ cast-be/datatransfers/video.go | 9 +++++++-- cast-be/handlers/auth.go | 1 + cast-be/handlers/video.go | 7 ++++--- cast-be/models/video.go | 10 ++++++++-- 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/cast-be/controller/v1/video.go b/cast-be/controller/v1/video.go index dab421b..b5d20c1 100644 --- a/cast-be/controller/v1/video.go +++ b/cast-be/controller/v1/video.go @@ -143,6 +143,7 @@ func (c *VideoControllerAuth) EditVideo(_ string) datatransfers.Response { Title: video.Title, Description: video.Description, Tags: strings.Split(video.Tags, ","), + Unlisted: video.Unlisted, }, c.Controller, c.userID) if err != nil { fmt.Printf("[VideoControllerAuth::EditVideo] failed editing video. %+v\n", err) @@ -190,6 +191,7 @@ func (c *VideoControllerAuth) UploadVideo(_ string) datatransfers.Response { Title: upload.Title, Description: upload.Description, Tags: strings.Split(upload.Tags, ","), + Unlisted: upload.Unlisted, }, c.Controller, c.userID) if err != nil { fmt.Printf("[VideoControllerAuth::UploadVideo] failed creating video. %+v\n", err) diff --git a/cast-be/datatransfers/video.go b/cast-be/datatransfers/video.go index 6f0c476..c9f6a38 100644 --- a/cast-be/datatransfers/video.go +++ b/cast-be/datatransfers/video.go @@ -17,6 +17,7 @@ type Video struct { Views int `json:"views" bson:"views"` Duration int64 `json:"duration,omitempty" bson:"duration"` // only for VODs IsLive bool `json:"is_live" bson:"is_live"` // only for Live + Unlisted bool `json:"unlisted" bson:"unlisted"` Pending bool `json:"pending" bson:"pending"` Resolutions int `json:"resolutions" bson:"resolutions"` // 0:None, 1:180p, 2:360p, 3:480p, 4:720p, 5:1080p, only for VODs Likes int `json:"likes" bson:"likes"` @@ -35,8 +36,8 @@ type VideoInsert struct { Description string `bson:"description"` Tags []string `bson:"tags"` Views int `json:"views" bson:"views"` - Duration int64 `bson:"duration"` // only for VODs - IsLive bool `bson:"is_live"` // only for Live + IsLive bool `bson:"is_live"` // only for Live, always set to true for VODs + Unlisted bool `bson:"unlisted"` Resolutions int `bson:"resolutions"` // 0:None, 1:180p, 2:360p, 3:480p, 4:720p, 5:1080p, only for VODs CreatedAt time.Time `bson:"created_at"` } @@ -45,12 +46,14 @@ type VideoUploadForm struct { Title string `form:"title"` Description string `form:"description"` Tags string `form:"tags"` + Unlisted bool `form:"unlisted"` } type VideoUpload struct { Title string Description string Tags []string + Unlisted bool } type VideoEditForm struct { @@ -58,6 +61,7 @@ type VideoEditForm struct { Title string `form:"title"` Description string `form:"description"` Tags string `form:"tags"` + Unlisted bool `form:"unlisted"` } type VideoEdit struct { @@ -65,6 +69,7 @@ type VideoEdit struct { Title string Description string Tags []string + Unlisted bool } type Comment struct { diff --git a/cast-be/handlers/auth.go b/cast-be/handlers/auth.go index 775a5f6..47d0eb9 100644 --- a/cast-be/handlers/auth.go +++ b/cast-be/handlers/auth.go @@ -47,6 +47,7 @@ func (m *module) Register(idToken datatransfers.UserRegister) (err error) { Description: "Welcome to my stream!", Resolutions: -1, IsLive: false, + Unlisted: false, }); err != nil { _ = m.db.userOrm.DeleteOneByID(user.ID) fmt.Printf("[Register] Failed adding %s live video entry. %+v\n", user.Username, err) diff --git a/cast-be/handlers/video.go b/cast-be/handlers/video.go index 3ebdae2..d1f28bb 100644 --- a/cast-be/handlers/video.go +++ b/cast-be/handlers/video.go @@ -97,9 +97,9 @@ func (m *module) CreateVOD(upload data.VideoUpload, controller beego.Controller, Author: userID, Description: upload.Description, Tags: upload.Tags, + IsLive: true, // must be set to true for VODs + Unlisted: upload.Unlisted, Views: 0, - Duration: 0, - IsLive: true, Resolutions: 0, CreatedAt: time.Now(), }); err != nil { @@ -179,12 +179,13 @@ func (m *module) UpdateVideo(video data.VideoEdit, controller beego.Controller, Author: userID, Description: video.Description, Tags: video.Tags, + Unlisted: video.Unlisted, }); err != nil { return errors.New(fmt.Sprintf("[UpdateVideo] error updating video. %+v", err)) } // Retrieve thumbnail var thumbnail multipart.File - if thumbnail, _, err = controller.GetFile("thumbnail"); err!= nil { + if thumbnail, _, err = controller.GetFile("thumbnail"); err != nil { if err == http.ErrMissingFile { return nil } else { diff --git a/cast-be/models/video.go b/cast-be/models/video.go index 552200f..c9df857 100644 --- a/cast-be/models/video.go +++ b/cast-be/models/video.go @@ -48,6 +48,7 @@ func (o *videoOrm) GetRecent(variant string, count int, offset int) (result []da {{"$match", bson.D{{"type", variant}}}}, {{"$match", bson.D{{"resolutions", bson.D{{"$ne", 0}}}}}}, {{"$match", bson.D{{"is_live", true}}}}, + {{"$match", bson.D{{"unlisted", false}}}}, {{"$sort", bson.D{{"created_at", -1}, {"_id", 1}}}}, {{"$skip", offset}}, {{"$limit", count}}, @@ -75,6 +76,7 @@ func (o *videoOrm) GetLiked(userID string, count int, offset int) (result []data if query, err = o.collection.Aggregate(context.Background(), mongo.Pipeline{ {{"$match", bson.D{{"resolutions", bson.D{{"$ne", 0}}}}}}, {{"$match", bson.D{{"is_live", true}}}}, + {{"$match", bson.D{{"unlisted", false}}}}, {{"$sort", bson.D{{"created_at", -1}, {"_id", 1}}}}, {{"$lookup", bson.D{ {"from", constants.DBCollectionLike}, @@ -111,6 +113,7 @@ func (o *videoOrm) GetSubscribed(userID string, count int, offset int) (result [ if query, err = o.collection.Aggregate(context.Background(), mongo.Pipeline{ {{"$match", bson.D{{"resolutions", bson.D{{"$ne", 0}}}}}}, {{"$match", bson.D{{"is_live", true}}}}, + {{"$match", bson.D{{"unlisted", false}}}}, {{"$sort", bson.D{{"created_at", -1}, {"_id", 1}}}}, {{"$lookup", bson.D{ {"from", constants.DBCollectionSubscription}, @@ -147,6 +150,7 @@ func (o *videoOrm) GetTrending(count int, offset int) (result []datatransfers.Vi if query, err = o.collection.Aggregate(context.Background(), mongo.Pipeline{ {{"$match", bson.D{{"resolutions", bson.D{{"$ne", 0}}}}}}, {{"$match", bson.D{{"is_live", true}}}}, + {{"$match", bson.D{{"unlisted", false}}}}, {{"$lookup", bson.D{ {"from", constants.DBCollectionLike}, {"localField", "hash"}, @@ -185,7 +189,7 @@ func (o *videoOrm) GetTrending(count int, offset int) (result []datatransfers.Vi func (o *videoOrm) GetAllVODByAuthor(author string) (videos []datatransfers.Video, err error) { query := &mongo.Cursor{} - if query, err = o.collection.Aggregate(context.Background(), mongo.Pipeline{ + if query, err = o.collection.Aggregate(context.Background(), mongo.Pipeline{ // unlisted VODs included {{"$match", bson.D{{"author", author}}}}, {{"$match", bson.D{{"type", constants.VideoTypeVOD}}}}, {{"$sort", bson.D{{"created_at", -1}, {"_id", 1}}}}, @@ -210,7 +214,7 @@ func (o *videoOrm) GetAllVODByAuthor(author string) (videos []datatransfers.Vide func (o *videoOrm) GetAllVODByAuthorPaginated(author string, count int, offset int) (videos []datatransfers.Video, err error) { query := &mongo.Cursor{} - if query, err = o.collection.Aggregate(context.Background(), mongo.Pipeline{ + if query, err = o.collection.Aggregate(context.Background(), mongo.Pipeline{ // unlisted VODs included {{"$match", bson.D{{"author", author}}}}, {{"$match", bson.D{{"type", constants.VideoTypeVOD}}}}, {{"$sort", bson.D{{"created_at", -1}, {"_id", 1}}}}, @@ -251,6 +255,7 @@ func (o *videoOrm) Search(queryString string, count int, offset int) (result []d {{"$match", bson.D{{"$text", bson.D{{"$search", queryString}}}}}}, {{"$match", bson.D{{"resolutions", bson.D{{"$ne", 0}}}}}}, {{"$match", bson.D{{"is_live", true}}}}, + {{"$match", bson.D{{"unlisted", false}}}}, {{"$sort", bson.D{{"views", -1}, {"created_at", -1}, {"_id", 1}}}}, {{"$skip", offset}}, {{"$limit", count}}, @@ -397,6 +402,7 @@ func (o *videoOrm) EditVideo(video datatransfers.VideoInsert) (err error) { {"title", video.Title}, {"description", video.Description}, {"tags", video.Tags}, + {"unlisted", video.Unlisted}, }}}, ).Err() } From 2c09c6973bdb113936e62335ef190d0a341eea6d Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 17:40:25 +1000 Subject: [PATCH 10/13] feat: selective notification based on video listing --- cast-be/handlers/rtmp.go | 16 +++++++++------- cast-be/handlers/transcode.go | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cast-be/handlers/rtmp.go b/cast-be/handlers/rtmp.go index d088988..4fe0f28 100644 --- a/cast-be/handlers/rtmp.go +++ b/cast-be/handlers/rtmp.go @@ -64,13 +64,15 @@ func (m *module) CreateRTMPUpLink() { return } fmt.Printf("[RTMPUpLink] UpLink for %s connected\n", username) - m.BroadcastNotificationSubscriber(video.Author.ID, datatransfers.NotificationOutgoing{ - Message: fmt.Sprintf("%s just went live! Watch now!", video.Author.Name), - Name: video.Author.Name, - Username: video.Author.Username, - Hash: video.Hash, - CreatedAt: time.Now(), - }) + if !video.Unlisted { + m.BroadcastNotificationSubscriber(video.Author.ID, datatransfers.NotificationOutgoing{ + Message: fmt.Sprintf("%s just went live! Watch now!", video.Author.Name), + Name: video.Author.Name, + Username: video.Author.Username, + Hash: video.Hash, + CreatedAt: time.Now(), + }) + } m.live.mutex.Unlock() } else { fmt.Printf("[RTMPUpLink] UpLink for %s already exists\n", username) diff --git a/cast-be/handlers/transcode.go b/cast-be/handlers/transcode.go index 66d7e3b..451cb9f 100644 --- a/cast-be/handlers/transcode.go +++ b/cast-be/handlers/transcode.go @@ -54,7 +54,7 @@ func (m *module) TranscodeListenerWorker() { CreatedAt: time.Now(), }) } - if resolution == 1 { + if !video.Unlisted && resolution == 1 { m.BroadcastNotificationSubscriber(video.Author.ID, datatransfers.NotificationOutgoing{ Message: fmt.Sprintf("%s just uploaded %s! Watch now!", video.Author.Name, video.Title), Name: video.Author.Name, From 4c00d3c43caf838a6850ce3d95d5212aee281115 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 17:42:26 +1000 Subject: [PATCH 11/13] refactor: improved styling --- cast-fe/src/views/Scene.jsx | 5 ++++- cast-fe/src/views/Subscribed.jsx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cast-fe/src/views/Scene.jsx b/cast-fe/src/views/Scene.jsx index 77dd572..c969e8b 100644 --- a/cast-fe/src/views/Scene.jsx +++ b/cast-fe/src/views/Scene.jsx @@ -481,7 +481,10 @@ class Scene extends Component {
Subscribed From 6f4fff6702d7f7978f4c2b6fc8f77e19830a34f0 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 6 Feb 2021 18:51:17 +1000 Subject: [PATCH 12/13] feat: added cast unlisted flag editing --- cast-fe/src/components/CastEditable.jsx | 116 ++++++++++++++++-------- cast-fe/src/views/Manage.jsx | 24 ++++- 2 files changed, 103 insertions(+), 37 deletions(-) diff --git a/cast-fe/src/components/CastEditable.jsx b/cast-fe/src/components/CastEditable.jsx index 583fd2f..5ea94c3 100644 --- a/cast-fe/src/components/CastEditable.jsx +++ b/cast-fe/src/components/CastEditable.jsx @@ -41,6 +41,7 @@ class CastEditable extends Component { : [], description: this.props.video.description, thumbnail: api.cdn.thumbnail(this.props.video.hash), + unlisted: this.props.video.unlisted, error_title: "", error_tags: "", error_description: "", @@ -93,6 +94,7 @@ class CastEditable extends Component { before: { title: this.state.title, tags: this.state.tags, + unlisted: this.state.unlisted, description: this.state.description, thumbnail: this.state.thumbnail, }, @@ -253,6 +255,7 @@ class CastEditable extends Component { form.append("title", this.state.title); form.append("description", this.state.description); form.append("tags", this.state.tags.map((tag) => tag.text).join(",")); + form.append("unlisted", this.state.unlisted); if (this.state.new_thumbnail) form.append("thumbnail", this.state.new_thumbnail); api.cast @@ -402,7 +405,12 @@ class CastEditable extends Component {
@@ -461,42 +469,75 @@ class CastEditable extends Component {
)} -
+
{this.state.editing ? ( - - this.setState({ error_tags: "" })} - handleInputBlur={() => - this.validate("tags", this.state.tags) - } - handleTagClick={this.handleTagClick} - /> - {this.state.error_tags && ( -
{this.state.error_tags}
- )} -
+ <> +
+ + this.setState({ unlisted: !this.state.unlisted }) + } + label={ + <> + Unlisted + + cast accessible only via direct link + + + } + /> +
+ + + this.setState({ error_tags: "" }) + } + handleInputBlur={() => + this.validate("tags", this.state.tags) + } + handleTagClick={this.handleTagClick} + /> + {this.state.error_tags && ( +
+ {this.state.error_tags} +
+ )} +
+ ) : (
+ {this.state.unlisted && ( + + Unlisted + + )} {this.state.tags && Object.values(this.state.tags).map((tag) => ( @@ -508,7 +549,7 @@ class CastEditable extends Component {
{this.state.editing ? (
e.preventDefault()}> - + tag.text).join(",")); + form.append("unlisted", this.state.unlisted); form.append("thumbnail", this.state.thumbnail); form.append("video", this.state.video); api.cast @@ -324,7 +326,7 @@ class Manage extends Component { onBlur={this.handleChange} onChange={this.handleChange} as={"textarea"} - rows={7} + rows={8} isInvalid={!!this.state.error_description} disabled={this.state.uploading} /> @@ -419,10 +421,30 @@ class Manage extends Component {
+ + + this.setState({ unlisted: !this.state.unlisted }) + } + label={ + <> + Unlisted{" "} + + cast accessible only via direct link + + + } + /> +