[Electron + Angular + TypeScript] Venobo Streaming App

Weasel

👄 I'd intercept me
Nov 25, 2011
4,128
2,456
Cleaned the thread and warned everyone who either insulted other users or started off-topic posting. This counts for both @Sentinel and @Aeternum - if any of you can't behave, I'll warn you for every single off-topic or insulting post, even if it are multiple on one thread. You're both good developers - help each other with constructive critism instead of slandering each other.
 

MayoMayn

BestDev
Oct 18, 2016
1,423
683
This looks amazing, good luck :D
Thanks man!
 
After going through some simplicity with ReactJS, I must say I really enjoy this library, it especially makes Electron development 100 times easier.
Just gone through in my head what I want to do with the TMDb API, and decided to code some simple parts of it.
The current component is mostly just for trying out React, so it will most likely be improved a lot before production.
PHP:
import React from 'react'
import axios from 'axios'

export default class TMDb extends React.Component {

  constructor(props) {
    //super(props)

    this.tmdb = require(__dirname + '/../config.json').tmdb

    this.state = {
      api: `${this.tmdb.api}/${props.type}/${props.id}`,
      add: `?api_key=${this.tmdb.key}&language=${props.lang}`
    }
  }

  setApi(type, id) {
    this.setState({api: `${this.tmdb.api}/${type}/${id}`})
  }

  setAdd(lang) {
    this.setState({add: `?api_key=${this.tmdb.key}&language=${lang}`})
  }

  getSimilarMovies() {
    return this.tmdbGet(`/similar${this.state.add}&page=1`).data
  }

  getDetails() {
    let details = this.tmdbGet(`${this.state.add}`).data

    return details
  }

  tmdbGet(extra = '') {
    axios.get(`${this.state.api}${extra}`)
      .then((response) => {
        return response
      })
  }

}
 
Just a preview of the Window Component for all the curious folks
PHP:
import React from 'react'
const win = window.require('electron').remote.getCurrentWindow()

export default class Window extends React.Component {

  constructor(props) {
    super(props)

    this.handleClose = this.handleClose.bind(this)
    this.handleMinimize = this.handleMinimize.bind(this)
    this.handleMaximize = this.handleMaximize.bind(this)
  }

  handleClose() {
    win.close()
  }

  handleMinimize() {
    win.minimize()
  }

  handleMaximize() {
    if(!win.isMaximized()) {
        win.maximize()
    } else {
        win.unmaximize()
    }
  }

  render() {
    return (
      <div className="menu-window">
        <span className="menu-button close" onClick={this.handleClose}></span>
        <span className="menu-button minimize" onClick={this.handleMinimize}></span>
        {this.props.maximize ? (
          <span className="menu-button maximize" onClick={this.handleMaximize}></span>
        ) : (
          <span className="menu-button inactive"></span>
        )}
      </div>
    )
  }

}
There's sadly this thing with renders in ReactJS, that it can only return a single element. So let's say you got five different divs in the renderer, then you'd have to wrap them inside a div so that it only returns a single element. Possibly ruin of CSS styles
 
#UPDATES
Added the below components to the app

 
I've created a git repo for this project:
 

MayoMayn

BestDev
Oct 18, 2016
1,423
683
You're making some good progress with this. Looks really good so far.
Haha yeah, I've definitely put some time into this.
Didn't take a look at the time, so I went to bed at 6am, because I wanted to restructure the whole project.
Thanks for the feedback
 
#UPDATES
I've managed to code the app responsive.
I think I will get rid of that horrible scrollbar next.

BPaI
 

griimnak

You're a slave to the money then you die
Jul 20, 2013
955
794
Haha yeah, I've definitely put some time into this.
Didn't take a look at the time, so I went to bed at 6am, because I wanted to restructure the whole project.
Thanks for the feedback
 
#UPDATES
I've managed to code the app responsive.
I think I will get rid of that horrible scrollbar next.

BPaI
Coming along nicely, looking forward to all the logical stuff like user view history, ect.
I'd probably start that stuff soon if i were you, i'd hate to see you put all the effort into the design then bail on the logic.
 

MayoMayn

BestDev
Oct 18, 2016
1,423
683
Coming along nicely, looking forward to all the logical stuff like user view history, ect.
I'd probably start that stuff soon if i were you, i'd hate to see you put all the effort into the design then bail on the logic.
Same here, I've just not begun all the logical stuff on the app yet, since I need to understand React atleast 90% first.
 

Weasel

👄 I'd intercept me
Nov 25, 2011
4,128
2,456
How is that even close to being similar? That's just an app that you can play music from using SoundCloud's API.
I guess he's talking about the design, and I can see where he's coming from. But eventually everything will look like something else, as almost everything has already been done (atleast, if you want to keep it really minimalistic).
 

MayoMayn

BestDev
Oct 18, 2016
1,423
683
I guess he's talking about the design, and I can see where he's coming from. But eventually everything will look like something else, as almost everything has already been done (atleast, if you want to keep it really minimalistic).
Oh yeah right, I suddenly got confused. Actually I got the design idea from this below.
zoommy-screen-1-46d3d27f0e6c4a09844faea2f152bab0.png
 

griimnak

You're a slave to the money then you die
Jul 20, 2013
955
794
Hmmm your project looks really familiar...

That's actually pretty dumb of you to say.

The only similarity I can honestly see here is the two column design with side bar, and black osx window frame.
21a8bf0625604e38a3273da2eb3fd65e.png


Also, I'm pretty sure if @Sentinel ripped this exact project he would of kept the good design ideas like the top left player card and top right gear and the left/right navi next to window charms.
BPaI


And from the looks of the code, @Sentinel is actually doing it more neater than cloudnode
6f934f1a559c48f095f26f5a08842bf6.png
 

MayoMayn

BestDev
Oct 18, 2016
1,423
683
That's actually pretty dumb of you to say.

The only similarity I can honestly see here is the two column design with side bar, and black osx window frame.
21a8bf0625604e38a3273da2eb3fd65e.png


Also, I'm pretty sure if @Sentinel ripped this exact project he would of kept the good design ideas like the top left player card and top right gear and the left/right navi next to window charms.
BPaI


And from the looks of the code, @Sentinel is actually doing it more neater than cloudnode
6f934f1a559c48f095f26f5a08842bf6.png
Well I really do wish I had the experience to code a design like that, but unfortunately I don't.
I got my design ideas from
 

Menkz

Member
Jul 9, 2010
374
167
There's not much you can do with a streaming app either, i mean - spotify has a similar style to both of these -
 

MayoMayn

BestDev
Oct 18, 2016
1,423
683
There's not much you can do with a streaming app either, i mean - spotify has a similar style to both of these -
Then it's good it's not an audio streaming app I'm developing :D
 
#UPDATES
If all goes as planned, there will be released a beta version of the app the weekend after this one.
Adding tons of movies is easy, but it's boring, so what I am planning to do, is make some sort of request page for the community, where people can vote for whatever movies or tv show they'd like to see added next. Also some users will be given a rank, so they have the opportunity to add new documents to the database, so that it becomes more community related.

Because of my school game development project this week, I haven't really found any energy to code on this when I get home, so the Git will first be updated on sunday.

I might also switch out React with some other front-end framework. In my opinion it really decreases your productivity, since there's a lot of stuff it doesnt allow/have the capability to work with.

Haven't found a decent name for the app. Primely seems way too unrelated and a lot of people I know are having problems pronouncing it (they're morons so probably why)
 
#UPDATES
Instead of writing all my updates, I will instead be posting videos on YouTube to show the progress.
Currently I've coded the quick search function


 
Well, I decided to ditch the other design as it was trash.
Here's some screens of the new:
c2xNs6K.png

UGqehrU.png

Don't mind the working title.
 

griimnak

You're a slave to the money then you die
Jul 20, 2013
955
794
This was beginning to look good:
But now you ditched the design -.-
 

JynX

Posting Freak
Feb 6, 2016
710
438
Ty, but well I didn't quite like it :p
 
Screenshot of the new login:
bLcyWPV.png
Hmm it looks good, but it doesn't make me think movies or TV in general. It looks like a login but not for something of this nature. But that's just my 2 cents
 

MayoMayn

BestDev
Oct 18, 2016
1,423
683
Hmm it looks good, but it doesn't make me think movies or TV in general. It looks like a login but not for something of this nature. But that's just my 2 cents
Nah, you're definitely right.
Relevant or not, it still looks quite nice.
The design before just looked way too shady (and definitely illegal kinda)
 
#UPDATES
I've decided to code an offline mode aswell as a caching system to get faster performance.
Everytime a HTTP requests gets made, it caches the data for 1 hour otherwise it caches new data, or if the computer is offline, it'll just use the latest cache.
components/cache.js
PHP:
import config from '../../config'
import fs from 'fs'
import path from 'path'
import rimraf from 'rimraf'
import md5 from 'crypto-js/md5'

export default class Cache {

  static write(key, data, callback) {
    if(data instanceof String) data = data.toString()
    if(typeof data != "string") data = JSON.stringify(data)

    this.exists(key, (res) => {
      if(res) this.purgeSync(key)

      fs.writeFileSync(this.getPath(key), data, {flag: 'wx'})
      callback(data)
    })
  }

  static read(key, callback) {
    let data = fs.readFileSync(this.getPath(key))
    callback(data.toString())
  }

  static exists(key, callback) {
    fs.stat(this.getPath(key), (err, stat) => {
      callback(!err, stat)
    })
  }

  static isExpired(key, callback) {
    this.exists(key, (res, stat) => {
      if(!res) {
        callback(true)
      } else {
        let now = new Date().getTime(),
            endTime = new Date(stat.ctime).getTime() + 3600000

        callback(now > endTime)
      }
    })
  }

  static getPath(key) {
    return path.join(config.CACHE_PATH, md5(key) + '.js')
  }

  static purge(key, callback) {
    fs.unlink(this.getPath(key), callback)
  }

  static purgeSync(key) {
    return fs.unlinkSync(this.getPath(key))
  }

  static trash(callback) {
    rimraf(config.CACHE_PATH, callback)
  }

}

components/http.js
PHP:
import Cache from './cache'
import Axios from 'axios'

export default class HTTP {

  static get(url, callback) {
    if(navigator.onLine) {
      Axios.get(url)
        .then((res) => {
          Cache.isExpired(url, (is) => {
            if(!is) {
              Cache.read(url, callback)
            } else {
              Cache.write(url, res.data, callback)
            }
          })
        })
        .catch((err) => {
          console.log(err)
          this.parse(url, callback)
        })
    } else {
      this.parse(url, callback)
    }
  }

  static post() {

  }

  static parse(url, callback) {
    Cache.exists(url, (res) => {
      if(res) {
        Cache.read(url, callback)
      } else {
        console.log("something went wrong with get requests, and cache doesnt exist")
      }
    })
  }

}

Still need some fixes but close being there.
 

Users who are viewing this thread

Top