├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gruntfile.coffee
├── LICENSE.txt
├── README.md
├── make_butter.sh
├── package.json
├── screenshot.png
└── src
├── assets
├── css
│ └── splash.css
├── fonts
│ ├── FontAwesome.otf
│ ├── Material-Design-Iconic-Font.ttf
│ ├── Material-Design-Iconic-Font.woff
│ ├── OpenSans-Bold.svg
│ ├── OpenSans-Bold.woff
│ ├── OpenSans-Regular.svg
│ ├── OpenSans-Regular.woff
│ ├── OpenSans-Semibold.svg
│ ├── OpenSans-Semibold.woff
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ ├── vjs.eot
│ ├── vjs.svg
│ ├── vjs.ttf
│ └── vjs.woff
├── images
│ ├── butter-logo.png
│ ├── butter-logo.svg
│ ├── flags
│ │ ├── ab.svg
│ │ ├── ad.svg
│ │ ├── ae.svg
│ │ ├── af.svg
│ │ ├── ag.svg
│ │ ├── ai.svg
│ │ ├── al.svg
│ │ ├── am.svg
│ │ ├── aq.svg
│ │ ├── ar.svg
│ │ ├── as.svg
│ │ ├── at.svg
│ │ ├── au.svg
│ │ ├── aw.svg
│ │ ├── ax.svg
│ │ ├── az.svg
│ │ ├── ba.svg
│ │ ├── bb.svg
│ │ ├── bd.svg
│ │ ├── be.svg
│ │ ├── bf.svg
│ │ ├── bg.svg
│ │ ├── bh.svg
│ │ ├── bi.svg
│ │ ├── bj.svg
│ │ ├── bl.svg
│ │ ├── bm.svg
│ │ ├── bn.svg
│ │ ├── bo.svg
│ │ ├── bq.svg
│ │ ├── br.svg
│ │ ├── bs.svg
│ │ ├── bt.svg
│ │ ├── bv.svg
│ │ ├── bw.svg
│ │ ├── by.svg
│ │ ├── bz.svg
│ │ ├── ca.svg
│ │ ├── cc.svg
│ │ ├── cd.svg
│ │ ├── cf.svg
│ │ ├── cg.svg
│ │ ├── ch.svg
│ │ ├── ci.svg
│ │ ├── ck.svg
│ │ ├── cl.svg
│ │ ├── cm.svg
│ │ ├── cn.svg
│ │ ├── co.svg
│ │ ├── cr.svg
│ │ ├── cu.svg
│ │ ├── cv.svg
│ │ ├── cw.svg
│ │ ├── cx.svg
│ │ ├── cy.svg
│ │ ├── cz.svg
│ │ ├── de.svg
│ │ ├── dj.svg
│ │ ├── dk.svg
│ │ ├── dm.svg
│ │ ├── do.svg
│ │ ├── dz.svg
│ │ ├── ec.svg
│ │ ├── ee.svg
│ │ ├── eg.svg
│ │ ├── eh.svg
│ │ ├── england.svg
│ │ ├── er.svg
│ │ ├── es.svg
│ │ ├── et.svg
│ │ ├── europeanunion.svg
│ │ ├── fi.svg
│ │ ├── fj.svg
│ │ ├── fk.svg
│ │ ├── fm.svg
│ │ ├── fo.svg
│ │ ├── fr.svg
│ │ ├── ga.svg
│ │ ├── gb.svg
│ │ ├── gd.svg
│ │ ├── ge.svg
│ │ ├── gf.svg
│ │ ├── gg.svg
│ │ ├── gh.svg
│ │ ├── gi.svg
│ │ ├── gl.svg
│ │ ├── gm.svg
│ │ ├── gn.svg
│ │ ├── gp.svg
│ │ ├── gq.svg
│ │ ├── gr.svg
│ │ ├── gs.svg
│ │ ├── gt.svg
│ │ ├── gu.svg
│ │ ├── gw.svg
│ │ ├── gy.svg
│ │ ├── hk.svg
│ │ ├── hm.svg
│ │ ├── hn.svg
│ │ ├── hr.svg
│ │ ├── ht.svg
│ │ ├── hu.svg
│ │ ├── id.svg
│ │ ├── ie.svg
│ │ ├── il.svg
│ │ ├── im.svg
│ │ ├── in.svg
│ │ ├── io.svg
│ │ ├── iq.svg
│ │ ├── ir.svg
│ │ ├── is.svg
│ │ ├── it.svg
│ │ ├── je.svg
│ │ ├── jm.svg
│ │ ├── jo.svg
│ │ ├── jp.svg
│ │ ├── ke.svg
│ │ ├── kg.svg
│ │ ├── kh.svg
│ │ ├── ki.svg
│ │ ├── km.svg
│ │ ├── kn.svg
│ │ ├── kp.svg
│ │ ├── kr.svg
│ │ ├── kw.svg
│ │ ├── ky.svg
│ │ ├── kz.svg
│ │ ├── la.svg
│ │ ├── lb.svg
│ │ ├── lc.svg
│ │ ├── li.svg
│ │ ├── lk.svg
│ │ ├── lr.svg
│ │ ├── ls.svg
│ │ ├── lt.svg
│ │ ├── lu.svg
│ │ ├── lv.svg
│ │ ├── ly.svg
│ │ ├── ma.svg
│ │ ├── mc.svg
│ │ ├── md.svg
│ │ ├── me.svg
│ │ ├── mf.svg
│ │ ├── mg.svg
│ │ ├── mh.svg
│ │ ├── mk.svg
│ │ ├── ml.svg
│ │ ├── mm.svg
│ │ ├── mn.svg
│ │ ├── mo.svg
│ │ ├── mp.svg
│ │ ├── mq.svg
│ │ ├── mr.svg
│ │ ├── ms.svg
│ │ ├── mt.svg
│ │ ├── mu.svg
│ │ ├── mv.svg
│ │ ├── mw.svg
│ │ ├── mx.svg
│ │ ├── my.svg
│ │ ├── mz.svg
│ │ ├── na.svg
│ │ ├── nc.svg
│ │ ├── ne.svg
│ │ ├── nf.svg
│ │ ├── ng.svg
│ │ ├── ni.svg
│ │ ├── nl.svg
│ │ ├── no.svg
│ │ ├── none.svg
│ │ ├── northerncyprus.svg
│ │ ├── np.svg
│ │ ├── nr.svg
│ │ ├── nu.svg
│ │ ├── nz.svg
│ │ ├── om.svg
│ │ ├── pa.svg
│ │ ├── pe.svg
│ │ ├── pf.svg
│ │ ├── pg.svg
│ │ ├── ph.svg
│ │ ├── pk.svg
│ │ ├── pl.svg
│ │ ├── pm.svg
│ │ ├── pn.svg
│ │ ├── pr.svg
│ │ ├── ps.svg
│ │ ├── pt.svg
│ │ ├── pw.svg
│ │ ├── py.svg
│ │ ├── qa.svg
│ │ ├── re.svg
│ │ ├── ro.svg
│ │ ├── ru.svg
│ │ ├── rw.svg
│ │ ├── sa.svg
│ │ ├── sb.svg
│ │ ├── sc.svg
│ │ ├── scotland.svg
│ │ ├── sd.svg
│ │ ├── se.svg
│ │ ├── sg.svg
│ │ ├── sh.svg
│ │ ├── si.svg
│ │ ├── sj.svg
│ │ ├── sk.svg
│ │ ├── sl.svg
│ │ ├── sm.svg
│ │ ├── sn.svg
│ │ ├── so.svg
│ │ ├── southossetia.svg
│ │ ├── sr.svg
│ │ ├── ss.svg
│ │ ├── st.svg
│ │ ├── sv.svg
│ │ ├── sx.svg
│ │ ├── sy.svg
│ │ ├── sz.svg
│ │ ├── tc.svg
│ │ ├── td.svg
│ │ ├── tf.svg
│ │ ├── tg.svg
│ │ ├── th.svg
│ │ ├── tj.svg
│ │ ├── tk.svg
│ │ ├── tl.svg
│ │ ├── tm.svg
│ │ ├── tn.svg
│ │ ├── to.svg
│ │ ├── tr.svg
│ │ ├── tt.svg
│ │ ├── tv.svg
│ │ ├── tw.svg
│ │ ├── tz.svg
│ │ ├── ua.svg
│ │ ├── ug.svg
│ │ ├── um.svg
│ │ ├── unitednations.svg
│ │ ├── us.svg
│ │ ├── uy.svg
│ │ ├── uz.svg
│ │ ├── va.svg
│ │ ├── vc.svg
│ │ ├── ve.svg
│ │ ├── vg.svg
│ │ ├── vi.svg
│ │ ├── vn.svg
│ │ ├── vu.svg
│ │ ├── wales.svg
│ │ ├── wf.svg
│ │ ├── ws.svg
│ │ ├── xk.svg
│ │ ├── ye.svg
│ │ ├── yt.svg
│ │ ├── za.svg
│ │ ├── zm.svg
│ │ ├── zw.svg
│ │ └── zz.svg
│ └── icons
│ │ ├── Player
│ │ ├── Sound0.png
│ │ ├── Sound1.png
│ │ ├── Sound2.png
│ │ ├── Sound3.png
│ │ └── Subtitles.png
│ │ ├── devices
│ │ ├── airplay-icon.svg
│ │ ├── airplay-xbmc-icon.svg
│ │ ├── chromecast-icon.svg
│ │ ├── dlna-icon.svg
│ │ ├── external-bomi-icon.svg
│ │ ├── external-fleex-player-icon.svg
│ │ ├── external-icon.svg
│ │ ├── external-mpc-hc-icon.svg
│ │ ├── external-mplayer-icon.svg
│ │ ├── external-mpv-icon.svg
│ │ ├── external-smplayer-icon.svg
│ │ ├── external-vlc-icon.svg
│ │ └── local-icon.svg
│ │ ├── social
│ │ ├── blog.svg
│ │ ├── discuss.svg
│ │ ├── facebook.svg
│ │ ├── github.svg
│ │ ├── google-plus.svg
│ │ ├── twitter.svg
│ │ └── website.svg
│ │ └── topbar
│ │ ├── close-color.svg
│ │ ├── max-color.svg
│ │ └── min-color.svg
├── index.html
└── js
│ ├── socket.io.js
│ └── tweenmax.js
├── client
├── _app
│ ├── app.coffee
│ └── app.styl
├── about
│ ├── about.coffee
│ ├── about.html
│ └── about.styl
├── bookmarks
│ ├── bookmarks.coffee
│ └── bookmarks.html
├── browser
│ ├── browser.coffee
│ ├── browser.html
│ └── browser.styl
├── common-directives
│ ├── _common-directives.coffee
│ ├── _common-directives.styl
│ ├── external-open.coffee
│ ├── image-cycler.coffee
│ ├── image-loaded.coffee
│ ├── panel-manager.coffee
│ ├── panel-manager.styl
│ ├── parallax.coffee
│ └── search.coffee
├── containers
│ ├── _containers.coffee
│ ├── controls
│ │ ├── controls-container.coffee
│ │ ├── controls-container.html
│ │ └── controls-container.styl
│ ├── disclaimer
│ │ └── disclaimer-container.styl
│ ├── episode
│ │ ├── episode-container.coffee
│ │ ├── episode-container.html
│ │ └── episode-container.styl
│ ├── file-selector
│ │ └── file-selector-container.styl
│ ├── help
│ │ └── help-container.styl
│ ├── meta
│ │ ├── meta-container.coffee
│ │ └── meta-container.html
│ ├── people
│ │ ├── people-container.coffee
│ │ └── people-container.html
│ ├── rating
│ │ ├── rating-container.coffee
│ │ └── rating-container.html
│ ├── updater
│ │ └── updater-contaier.styl
│ └── view
│ │ ├── view-container.coffee
│ │ └── view-container.styl
├── detail
│ ├── detail.coffee
│ ├── detail.html
│ ├── detail.styl
│ ├── episode-modal.html
│ └── episode-model.styl
├── device-selector
│ ├── device-selector.coffee
│ ├── device-selector.html
│ └── device-selector.styl
├── filter-bar
│ ├── filter-bar-item.html
│ ├── filter-bar-item.styl
│ ├── filter-bar.coffee
│ ├── filter-bar.html
│ └── filter-bar.styl
├── gsap
│ ├── _gsap.coffee
│ ├── controllers
│ │ ├── grid-reveal.coffee
│ │ ├── gs-timeline-controller.coffee
│ │ └── test.html
│ ├── directives
│ │ ├── gs-pause.coffee
│ │ ├── gs-scale.coffee
│ │ ├── gs-states.coffee
│ │ └── gs-step.coffee
│ └── services
│ │ ├── $timeline.coffee
│ │ ├── gs-timeline.coffee
│ │ ├── log-build.coffee
│ │ └── utils.coffee
├── header
│ ├── header.coffee
│ ├── header.html
│ └── header.styl
├── page-header
│ ├── page-header.coffee
│ ├── page-header.html
│ └── page-header.styl
├── play-torrent
│ ├── play-torrent.coffee
│ └── play-torrent.html
├── plugins-manager
│ ├── app.coffee
│ └── service
│ │ ├── BrowserEngines.coffee
│ │ ├── GenericEngine.coffee
│ │ ├── GenericResultParser.coffee
│ │ ├── MatchTorrent.coffee
│ │ └── RequestService.coffee
├── providers
│ ├── cache.coffee
│ ├── trakttv.coffee
│ └── vodo.coffee
├── quality-icon
│ ├── quality-icon.coffee
│ └── quality-icon.html
├── quality-selector
│ ├── quality-selector.coffee
│ ├── quality-selector.html
│ └── quality-selector.styl
├── services
│ ├── bootstrap.coffee
│ ├── cloudflare-api.coffee
│ ├── collapse.coffee
│ ├── colors.coffee
│ ├── database.coffee
│ ├── external-players.coffee
│ ├── icons.coffee
│ ├── keep-awake.coffee
│ ├── language.coffee
│ ├── node-helpers.coffee
│ ├── player-service.coffee
│ ├── scroll.coffee
│ ├── sorters.coffee
│ ├── torrent-health.coffee
│ ├── utilities.coffee
│ ├── vibrant.coffee
│ └── xml.coffee
├── settings
│ ├── _settings.coffee
│ ├── services
│ │ ├── advanced-settings.coffee
│ │ └── settings.coffee
│ ├── settings.html
│ ├── settings.styl
│ └── templates
│ │ ├── settings-buttons.html
│ │ ├── settings-cache.html
│ │ ├── settings-connection.html
│ │ ├── settings-database.html
│ │ ├── settings-features.html
│ │ ├── settings-miscellaneous.html
│ │ ├── settings-playback.html
│ │ ├── settings-quality.html
│ │ ├── settings-remotecontrol.html
│ │ ├── settings-subtitles.html
│ │ ├── settings-title.html
│ │ ├── settings-trakttv.html
│ │ ├── settings-tvshowtime.html
│ │ └── settings-userui.html
├── sidebar
│ └── sidebar.styl
├── streamer
│ ├── provider.coffee
│ └── socket.coffee
├── torrents
│ ├── torrents.coffee
│ ├── torrents.html
│ └── torrents.styl
└── webchimera
│ ├── _plugins
│ ├── wc-analytics
│ │ └── wc-analytics.coffee
│ ├── wc-bottom-controls
│ │ ├── wc-bottom-controls.coffee
│ │ ├── wc-bottom-controls.styl
│ │ ├── wc-fullscreen-button
│ │ │ └── wc-fullscreen-button.coffee
│ │ ├── wc-play-pause-button
│ │ │ └── wc-play-pause-button.coffee
│ │ ├── wc-playback-button
│ │ │ └── wc-playback-button.coffee
│ │ ├── wc-scrub-bar
│ │ │ ├── wc-scrub-bar-cue-points.coffee
│ │ │ ├── wc-scrub-bar-current-time.coffee
│ │ │ └── wc-scrub-bar.coffee
│ │ ├── wc-subtitle
│ │ │ ├── wc-subtitle.coffee
│ │ │ └── wc-subtitle.styl
│ │ ├── wc-time-display
│ │ │ └── wc-time-display.coffee
│ │ └── wc-volume
│ │ │ ├── wc-mute-button.coffee
│ │ │ ├── wc-volume-bar.coffee
│ │ │ └── wc-volume.coffee
│ ├── wc-buffering
│ │ ├── wc-buffering.coffee
│ │ └── wc-buffering.styl
│ ├── wc-dash
│ │ └── wc-dash.coffee
│ ├── wc-ima-ads
│ │ ├── wc-ima-ads.coffee
│ │ └── wc-ima-ads.styl
│ ├── wc-overlay-play
│ │ ├── wc-overlay-play.coffee
│ │ └── wc-overlay-play.styl
│ ├── wc-poster
│ │ ├── wc-poster.coffee
│ │ └── wc-poster.styl
│ ├── wc-top-controls
│ │ ├── top-controls.coffee
│ │ ├── wc-close-button
│ │ │ └── wc-close-button.coffee
│ │ └── wc-top-controls.styl
│ └── wc-torrent-info
│ │ ├── wc-torrent-info.coffee
│ │ └── wc-torrent-info.styl
│ ├── _webchimera.coffee
│ ├── constants
│ └── wc-constants.coffee
│ ├── controllers
│ └── wc-controller.coffee
│ ├── directives
│ ├── chimerangular-container.styl
│ ├── chimerangular.coffee
│ ├── chimerangular.styl
│ ├── wc-loop.coffee
│ ├── wc-media.coffee
│ ├── wc-native-controls.coffee
│ ├── wc-next-video.coffee
│ ├── wc-next-video.styl
│ ├── wc-preload.coffee
│ └── wc-tracks.coffee
│ ├── services
│ ├── wc-config-loader.coffee
│ ├── wc-fullscreen-api.coffee
│ ├── wc-next-video.coffee
│ ├── wc-renderer.coffee
│ └── wc-utils.coffee
│ ├── views
│ └── directives
│ │ ├── wc-bottom-controls.html
│ │ ├── wc-buffering.html
│ │ ├── wc-close-button.html
│ │ ├── wc-fullscreen-button.html
│ │ ├── wc-media.html
│ │ ├── wc-mute-button.html
│ │ ├── wc-next-video.html
│ │ ├── wc-overlay-play.html
│ │ ├── wc-play-pause-button.html
│ │ ├── wc-playback-button.html
│ │ ├── wc-poster.html
│ │ ├── wc-scrub-bar-cue-points.html
│ │ ├── wc-scrub-bar.html
│ │ ├── wc-title.html
│ │ ├── wc-top-controls.html
│ │ ├── wc-torrent-info.html
│ │ └── wc-volume-bar.html
│ └── webchimera.html
├── lang
├── ar.json
├── az.json
├── bg.json
├── bn.json
├── bs.json
├── ca.json
├── cs.json
├── da.json
├── de.json
├── el.json
├── en-gb.json
├── en.json
├── en@pirate.json
├── eo.json
├── es-ar.json
├── es-mx.json
├── es.json
├── et.json
├── eu.json
├── fa.json
├── fi.json
├── fr.json
├── fy.json
├── gl.json
├── he.json
├── hi.json
├── hr.json
├── hu.json
├── id.json
├── is.json
├── it.json
├── ja.json
├── ka.json
├── kn.json
├── ko.json
├── ku-iq.json
├── ku.json
├── lt.json
├── lv.json
├── mk.json
├── ms.json
├── nb.json
├── nl.json
├── nn.json
├── pa.json
├── pl.json
├── pt-br.json
├── pt.json
├── ro.json
├── ru.json
├── si.json
├── sk.json
├── sl.json
├── sq.json
├── sr.json
├── sr@latin.json
├── sv.json
├── th.json
├── tr.json
├── uk.json
├── vi.json
├── zh-cn.json
└── zh-tw.json
├── scripts
├── app-menu.coffee
├── app-window.coffee
├── application.coffee
├── main.coffee
└── menus
│ ├── darwin.coffee
│ ├── linux.coffee
│ └── win32.coffee
├── server
├── ffmpegService.coffee
├── routeHandlers.coffee
├── socketActions.coffee
├── socketServer.coffee
├── streamOptions.coffee
├── streamServer.coffee
├── streamerEngine.coffee
├── throttle.coffee
├── torrentProgress.coffee
├── torrentStats.coffee
├── torrentStore.coffee
└── torrentUtils.coffee
└── vendor
├── js
├── angular-xmlrpc.js
└── socket.js
└── openssl
├── ia32
├── HashInfo.txt
├── OpenSSL License.txt
├── ReadMe.txt
├── libeay32.dll
├── openssl.exe
└── ssleay32.dll
├── shared
├── cacert.pem
├── certindex.txt
├── openssl.cnf
├── private
│ └── cakey.pem
└── serial
└── x64
├── HashInfo.txt
├── OpenSSL License.txt
├── ReadMe.txt
├── libeay32.dll
├── openssl.exe
└── ssleay32.dll
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | cache/
3 | lib-cov
4 | *.seed
5 | *.log
6 | *.csv
7 | *.dat
8 | *.out
9 | *.pid
10 | *.gz
11 |
12 | .idea/
13 | *.iml
14 |
15 | node_modules/
16 | src/app/vendor
17 | src/app/themes
18 | build/
19 |
20 | pids
21 | logs
22 | results
23 |
24 | npm-debug.log
25 |
26 | app.nw
27 |
28 | .sass-cache
29 | *-ck.js
30 | *.srt
31 | *.DS_Store
32 |
33 | # vim swap files
34 | *.swp
35 |
36 | src/app/css/app.css
37 | *.sublime-*
38 | dist/windows/*-Setup.exe
39 | dist/windows/update.exe
40 | dist/linux/linux-installer
41 | dist/linux/*.deb
42 | *.bat
43 | *.db
44 | *git.json
45 | *openvpn*
46 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "4.4.1"
4 | before_install: npm install -g grunt-cli grunt bower
5 | after_success:
6 | - grunt build
7 | notifications:
8 | email: false
9 | irc: "chat.freenode.net#butterdev"
10 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:14.04
2 |
3 | RUN apt-get --yes update && apt-get --yes upgrade
4 | RUN apt-get --yes install -y curl git python
5 |
6 | RUN curl -sL https://deb.nodesource.com/setup_0.12 | sudo bash -
7 | RUN apt-get --yes install -y nodejs
8 | RUN sudo npm install -g npm
9 |
10 | RUN nodejs --version
11 | RUN npm --version
12 |
13 | RUN git clone https://github.com/butterproject/butter-desktop-angular.git /opt/butter
14 |
15 | WORKDIR /opt/butter
16 | RUN npm install -g bower grunt-cli
17 | RUN npm install
18 | RUN grunt build
19 |
20 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/screenshot.png
--------------------------------------------------------------------------------
/src/assets/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/src/assets/fonts/Material-Design-Iconic-Font.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/Material-Design-Iconic-Font.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Material-Design-Iconic-Font.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/Material-Design-Iconic-Font.woff
--------------------------------------------------------------------------------
/src/assets/fonts/OpenSans-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/OpenSans-Bold.woff
--------------------------------------------------------------------------------
/src/assets/fonts/OpenSans-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/OpenSans-Regular.woff
--------------------------------------------------------------------------------
/src/assets/fonts/OpenSans-Semibold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/OpenSans-Semibold.woff
--------------------------------------------------------------------------------
/src/assets/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/src/assets/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/src/assets/fonts/vjs.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/vjs.eot
--------------------------------------------------------------------------------
/src/assets/fonts/vjs.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/vjs.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/vjs.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/fonts/vjs.woff
--------------------------------------------------------------------------------
/src/assets/images/butter-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/images/butter-logo.png
--------------------------------------------------------------------------------
/src/assets/images/flags/ag.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/flags/am.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/at.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ax.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/src/assets/images/flags/az.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/bd.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/assets/images/flags/be.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/bf.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/src/assets/images/flags/bg.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/bh.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/flags/bj.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/bq.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/bs.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/src/assets/images/flags/bv.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cd.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cf.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cg.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ch.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cl.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cm.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cn.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/flags/co.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cr.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cu.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cw.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/src/assets/images/flags/cz.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/flags/de.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/dj.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/dk.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/flags/dz.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/flags/england.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/europeanunion.svg:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/src/assets/images/flags/fo.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/src/assets/images/flags/fr.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ga.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gb.svg:
--------------------------------------------------------------------------------
1 |
2 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gf.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gg.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gh.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gl.svg:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gm.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gn.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gr.svg:
--------------------------------------------------------------------------------
1 |
2 |
25 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gw.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/gy.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ht.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/hu.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/src/assets/images/flags/id.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ie.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/is.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/flags/it.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/jm.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/flags/jo.svg:
--------------------------------------------------------------------------------
1 |
2 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/flags/jp.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/flags/kn.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/kw.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/assets/images/flags/la.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/flags/lc.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/lt.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/lv.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ly.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ma.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/flags/mc.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/assets/images/flags/mg.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/mm.svg:
--------------------------------------------------------------------------------
1 |
22 |
--------------------------------------------------------------------------------
/src/assets/images/flags/mr.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/flags/mv.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ne.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ng.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/src/assets/images/flags/nl.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/no.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/assets/images/flags/northerncyprus.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/assets/images/flags/pa.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/assets/images/flags/pk.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/pl.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/assets/images/flags/pr.svg:
--------------------------------------------------------------------------------
1 |
2 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ps.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/pw.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/flags/qa.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/flags/re.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ro.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ru.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/sc.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/scotland.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/assets/images/flags/sd.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/assets/images/flags/se.svg:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/src/assets/images/flags/sj.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/assets/images/flags/sn.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/so.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/flags/southossetia.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/assets/images/flags/sr.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ss.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/src/assets/images/flags/tf.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/tg.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/flags/th.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/flags/tl.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/assets/images/flags/to.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/flags/tr.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/flags/tt.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/assets/images/flags/tz.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ua.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/assets/images/flags/vc.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ve.svg:
--------------------------------------------------------------------------------
1 |
29 |
--------------------------------------------------------------------------------
/src/assets/images/flags/vn.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/flags/wf.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/ye.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/flags/za.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
--------------------------------------------------------------------------------
/src/assets/images/flags/zz.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/src/assets/images/icons/Player/Sound0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/images/icons/Player/Sound0.png
--------------------------------------------------------------------------------
/src/assets/images/icons/Player/Sound1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/images/icons/Player/Sound1.png
--------------------------------------------------------------------------------
/src/assets/images/icons/Player/Sound2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/images/icons/Player/Sound2.png
--------------------------------------------------------------------------------
/src/assets/images/icons/Player/Sound3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/images/icons/Player/Sound3.png
--------------------------------------------------------------------------------
/src/assets/images/icons/Player/Subtitles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/assets/images/icons/Player/Subtitles.png
--------------------------------------------------------------------------------
/src/assets/images/icons/social/blog.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/images/icons/social/discuss.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/images/icons/social/facebook.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/images/icons/social/github.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/images/icons/social/google-plus.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/images/icons/social/twitter.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/images/icons/social/website.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/client/_app/app.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app', [
4 | # vendor
5 | 'ngSanitize'
6 | 'ngMaterial'
7 | 'ngAnimate'
8 | 'ngAria'
9 |
10 | 'socket-io'
11 | 'xmlrpc'
12 |
13 | 'app.about'
14 | 'app.bookmarks'
15 | 'app.browser'
16 | 'app.common-directives'
17 | 'app.containers'
18 | 'app.detail'
19 | 'app.device-selector'
20 | 'app.filter-bar'
21 | 'app.header'
22 | 'app.gsTimelines'
23 | 'app.page-header'
24 | 'app.plugins'
25 | 'app.play-torrent'
26 | 'app.providers'
27 | 'app.quality-icon'
28 | 'app.quality-selector'
29 | 'app.services'
30 | 'app.settings'
31 | 'app.streamer'
32 | 'app.torrents'
33 | 'app.webchimera'
34 |
35 | ]
36 |
37 | .config ($compileProvider, $httpProvider, $mdThemingProvider) ->
38 |
39 | $compileProvider.debugInfoEnabled true
40 |
41 |
--------------------------------------------------------------------------------
/src/client/about/about.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.about', []
4 |
5 | .controller 'aboutController', (AdvSettings) ->
6 | vm = this
7 |
8 | vm.name = AdvSettings.get('branding').name
9 |
10 | # Social Links and Buttons
11 | vm.social_buttons =
12 | 'website':
13 | 'url': 'http://butterproject.org'
14 | 'label': 'Butter Website'
15 | 'blog':
16 | 'url': 'http://blog.butterproject.org'
17 | 'label': 'Butter Blog'
18 | 'discuss':
19 | 'url': 'https://www.reddit.com/r/ButterProject'
20 | 'label': 'Butter Forum'
21 | 'facebook':
22 | 'url': 'https://www.facebook.com/ButterProjectOrg'
23 | 'label': 'Butter Facebook'
24 | 'twitter':
25 | 'url': 'https://twitter.com/butterproject'
26 | 'label': 'Butter Twitter'
27 | 'google-plus':
28 | 'url': 'https://plus.google.com/communities/111003619134556931561'
29 | 'label': 'Butter Google+'
30 | 'github':
31 | 'url': 'https://github.com/butterproject/butter'
32 | 'label': 'Butter GitHub'
33 |
34 | .controller 'changelogController', ($scope, $http) ->
35 | $http.get('../../CHANGELOG.md').then ((response) ->
36 | $scope.content = response.data
37 | return
38 | ), (response) ->
39 | $scope.content = 'No Changelog file found!'
40 | return
41 |
42 | return
43 |
--------------------------------------------------------------------------------
/src/client/about/about.styl:
--------------------------------------------------------------------------------
1 | md-content#about
2 |
3 | pt-page-header
4 | position relative
5 | top -100px
6 | left 0px
7 | height auto
8 |
9 | section
10 | width 80%
11 | padding-left 40px
12 |
13 | p
14 | font-size 18px
15 |
16 | #changelog
17 | height 600px
18 |
19 | .md-button
20 | background-color none
21 |
22 | md-icon
23 | height 48px
24 | width 48px
25 | transition opacity 400ms ease-out
26 |
27 | &:hover
28 | opacity 0.4
29 |
30 | md-tooltip .md-content
31 | position relative
32 | opacity 1
33 |
--------------------------------------------------------------------------------
/src/client/bookmarks/bookmarks.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.bookmarks', []
4 |
5 | .controller 'bookmarksController', ->
6 |
--------------------------------------------------------------------------------
/src/client/bookmarks/bookmarks.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/client/bookmarks/bookmarks.html
--------------------------------------------------------------------------------
/src/client/common-directives/_common-directives.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.common-directives', []
4 |
--------------------------------------------------------------------------------
/src/client/common-directives/_common-directives.styl:
--------------------------------------------------------------------------------
1 | background-cycler >
2 | .ng-enter
3 | opacity: 0
4 | -webkit-transition: opacity 2s ease-in-out
5 | .ng-enter-active
6 | opacity: 1
7 | .ng-leave
8 | opacity: 1
9 | -webkit-transition: opacity 2s ease-in-out
10 | .ng-leave-active
11 | opacity: 0
12 | .ng-anchor
13 | transition: 0.5s linear all
14 |
15 | .bg-image
16 | position absolute
17 | width 100%
18 | top 0
19 | height 60vh
20 | z-index 1
21 | overflow hidden
22 | background-size cover
23 | background-repeat no-repeat
24 | -webkit-filter brightness(55%)
25 |
--------------------------------------------------------------------------------
/src/client/common-directives/external-open.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.common-directives'
4 |
5 | .directive 'extOpen', (ipc) ->
6 | scope: { link: '=' }
7 | link: (scope, element, attrs) ->
8 | open = ->
9 | ipc.send 'open-url-in-external', scope.link
10 |
11 | element.on 'click', open
12 |
13 | scope.$on '$destroy', ->
14 | element.off 'click', open
15 |
--------------------------------------------------------------------------------
/src/client/common-directives/image-cycler.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.common-directives'
4 |
5 | .directive 'backgroundCycler', ($compile, $animate, $q) ->
6 | restrict: 'E'
7 | link: (scope, element, attr) ->
8 | image = null
9 | imageScope = null
10 |
11 | $animate.enabled element
12 |
13 | scope.$watch 'browser.backdrop', (newImageUrl) ->
14 | if newImageUrl
15 | newScope = scope.$new()
16 | newScope.url = newImageUrl
17 |
18 | animations = []
19 |
20 | if image
21 | animations.push $animate.leave image
22 |
23 | image = angular.element ''
24 | newImage = $compile(image) newScope
25 |
26 | animations.push $animate.enter newImage, element, null
27 |
28 | $q.all(animations).then ->
29 | if imageScope
30 | imageScope.$destroy()
31 | imageScope = newScope
32 |
33 | return
34 |
35 | .directive 'backgroundImage', ($compile, $animate) ->
36 | restrict: 'E'
37 | template: '
'
38 | replace: true
39 | scope: true
40 | link: (scope, element, attr) ->
41 | if scope.url
42 | element.css 'background-image': 'url(' + scope.url + ')'
43 | return
44 |
--------------------------------------------------------------------------------
/src/client/common-directives/image-loaded.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.common-directives'
4 |
5 | .directive 'imageLoaded', ($timeout, $Vibrant) ->
6 | restrict: 'A'
7 | scope: { colors: '=', name: '=' }
8 | link: (scope, element, attrs) ->
9 | getPosterDetails = ->
10 | element.addClass 'fadein'
11 |
12 | $Vibrant.get(element[0], scope.name).then (colors) ->
13 | scope.colors = colors
14 |
15 | element.unbind 'load', getPosterDetails
16 | return
17 |
18 | element.bind 'load', getPosterDetails
19 |
20 | scope.$on '$destroy', ->
21 | element.unbind 'load', getPosterDetails
22 |
23 | return
24 |
--------------------------------------------------------------------------------
/src/client/common-directives/panel-manager.styl:
--------------------------------------------------------------------------------
1 | pt-panel
2 | display flex
3 | overflow hidden
4 | height 100vh
5 | position relative
6 | width 100%
7 | backface-visibility hidden
8 | will-change overflow
9 |
10 | pt-sidebar,
11 | pt-content
12 | overflow auto
13 | height auto
14 | -webkit-overflow-scrolling touch
15 | -ms-overflow-style none
16 |
17 | pt-sidebar::-webkit-scrollbar
18 | display none
19 |
20 | pt-content
21 | flex 1
22 |
23 | .splash-container
24 | height: 50%;
25 | left: 25%;
26 | top: 25%;
27 | z-index: 9999;
28 | width: 50%;
29 | position: absolute;
--------------------------------------------------------------------------------
/src/client/containers/_containers.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.containers', []
4 |
--------------------------------------------------------------------------------
/src/client/containers/controls/controls-container.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.containers'
4 |
5 | .directive 'ptControlsContainer', ->
6 | restrict: 'E'
7 | templateUrl: 'containers/controls/controls-container.html'
8 |
--------------------------------------------------------------------------------
/src/client/containers/controls/controls-container.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/client/containers/controls/controls-container.styl:
--------------------------------------------------------------------------------
1 | pt-controls-container
2 | position absolute
3 | display block
4 | height 180px
5 | width 100vw
6 | right 0
7 | bottom 0px
8 | background-color #111214
9 |
10 | .containers-controls
11 | margin-top 20px
12 | margin-left calc(((100vh - 240px - 50px) * 2 / 3) + 190px)
13 |
14 |
--------------------------------------------------------------------------------
/src/client/containers/episode/episode-container.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.containers'
4 |
5 | .directive 'ptEpisodeContainer', ->
6 | restrict: 'E'
7 | scope: { episodes: '=', selectedEpisode: '=' }
8 | templateUrl: 'containers/episode/episode-container.html'
9 | bindToController: true
10 | controllerAs: 'container'
11 | controller: ($scope) ->
12 | vm = this
13 |
14 | vm.selectEpisode = (episode) ->
15 | vm.selectedEpisode = episode
16 |
17 | return
18 |
--------------------------------------------------------------------------------
/src/client/containers/episode/episode-container.html:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/client/containers/meta/meta-container.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.containers'
4 |
5 | .directive 'ptMetaContainer', ->
6 | restrict: 'E'
7 | scope: { show: '=' }
8 | templateUrl: 'containers/meta/meta-container.html'
9 |
--------------------------------------------------------------------------------
/src/client/containers/meta/meta-container.html:
--------------------------------------------------------------------------------
1 |
2 |
11 |
{{ show.synopsis ? show.synopsis : 'Synopsis not available.' }}
12 |
13 |
14 | launchMore Info
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/client/containers/people/people-container.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.containers'
4 |
5 | .directive 'ptPeopleContainer', ->
6 | restrict: 'E'
7 | scope: { people: '=' }
8 | templateUrl: 'containers/people/people-container.html'
9 |
--------------------------------------------------------------------------------
/src/client/containers/people/people-container.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
![]()
5 |
6 |
7 | {{ person.name }}
8 |
9 |
10 | as {{ person.show_name }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/client/containers/rating/rating-container.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.containers'
4 |
5 | .directive 'ratingContainer', ->
6 | restrict: 'A'
7 | scope: { rating: '=' }
8 | bindToController: true
9 | templateUrl: 'containers/rating/rating-container.html'
10 | controller: 'ratingCtrl as rating'
11 |
12 | .controller 'ratingCtrl', ->
13 | vm = this
14 |
15 | # vm.rating.percentage is actually a value [1..10]
16 | vm.rounded = Math.round(vm.rating.percentage) / 2
17 |
18 | vm.stars = [1..5].map (i) ->
19 | if i > vm.rounded then (if vm.rounded % 1 > 0 and Math.ceil(vm.rounded) is i then 'star_half' else 'star_border') else 'star'
20 |
21 | return
22 |
--------------------------------------------------------------------------------
/src/client/containers/rating/rating-container.html:
--------------------------------------------------------------------------------
1 | {{ star }}
--------------------------------------------------------------------------------
/src/client/containers/view/view-container.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.containers'
4 |
5 | .directive 'ptViewContainer', ->
6 | restrict: 'E'
7 | transclude: true
8 | template: ''
9 | controller: 'ptViewController as view'
10 |
11 | .controller 'ptViewController', (Settings, $sce, torrentProvider, $state) ->
12 | vm = this
13 |
14 | vm.state = $state
15 |
16 | return
17 |
--------------------------------------------------------------------------------
/src/client/containers/view/view-container.styl:
--------------------------------------------------------------------------------
1 | pt-view-container
2 | background-color #191D22
3 | display block
4 | position relative
5 | height 100vh
6 |
7 | .main-container
8 | display block
9 | position relative
10 | height 100vh
--------------------------------------------------------------------------------
/src/client/detail/episode-modal.html:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 | Close
13 |
--------------------------------------------------------------------------------
/src/client/device-selector/device-selector.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.device-selector', []
4 |
5 | .directive 'ptDeviceSelector', ->
6 | scope: { selected: '=' }
7 | bindToController: true
8 | templateUrl: 'device-selector/device-selector.html'
9 | controller: 'deviceSelectController as devices'
10 |
11 | .controller 'deviceSelectController', (Settings) ->
12 | vm = this
13 |
14 | vm.items = Settings.avaliableDevices
15 | vm.selected = if Settings.chosenPlayer? then Settings.chosenPlayer else "local"
16 |
17 | vm.openMenu = ($mdOpenMenu, event) ->
18 | originatorEv = event
19 | $mdOpenMenu event
20 |
21 | vm.setItem = (id) ->
22 | Settings.chosenPlayer = vm.selected = id
23 |
24 | vm.setItem vm.selected
25 |
26 | return
27 |
--------------------------------------------------------------------------------
/src/client/device-selector/device-selector.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 | {{ devices.items[devices.selected].name }}
9 |
10 |
11 |
12 |
13 |
14 |
16 | {{ item.name }}
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/client/device-selector/device-selector.styl:
--------------------------------------------------------------------------------
1 | md-menu.device-selector
2 |
3 | .md-button
4 |
5 | transition opacity 400ms ease-out
6 | text-transform none
7 |
8 | &:hover
9 | opacity 0.4
10 |
--------------------------------------------------------------------------------
/src/client/filter-bar/filter-bar-item.html:
--------------------------------------------------------------------------------
1 |
4 | {{ item | titleCase }}
5 |
6 |
--------------------------------------------------------------------------------
/src/client/filter-bar/filter-bar-item.styl:
--------------------------------------------------------------------------------
1 | .filter-bar md-select-menu md-option
2 |
3 | transition opacity 400ms ease-out
4 |
5 | &:hover
6 | opacity 0.2
7 |
--------------------------------------------------------------------------------
/src/client/filter-bar/filter-bar.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.filter-bar', []
4 |
5 | .directive 'ptFilterBar', ->
6 | restrict: 'E'
7 | scope: { type: '=', onChange: '&' }
8 | bindToController: true
9 | templateUrl: 'filter-bar/filter-bar.html'
10 | controller: 'filterCtrl as filters'
11 |
12 | .controller 'filterCtrl', ($scope, genres, sorters, types) ->
13 | vm = this
14 |
15 | vm.menuOpen = null
16 |
17 | vm.list =
18 | sorters: sorters[vm.type]
19 | types: types[vm.type]
20 | genres: genres[vm.type]
21 |
22 | $scope.$watchCollection 'filters.params', (newParams, oldParams) ->
23 | if not angular.equals(newParams, oldParams) and angular.isDefined oldParams
24 | vm.onChange params: newParams
25 |
26 | return
27 |
28 | .directive 'ptFilterBarItem', ->
29 | restrict: 'E'
30 | bindToController: true
31 | scope: { items: '=?', selected: '=', label: '@', menuOpen: '=' }
32 | templateUrl: "filter-bar/filter-bar-item.html"
33 | controller: 'filterBarItemController as filter'
34 |
35 | .controller 'filterBarItemController', ->
36 | vm = this
37 |
38 | if not vm.selected
39 | vm.selected = vm.items[0]
40 |
41 | return
42 |
43 |
--------------------------------------------------------------------------------
/src/client/filter-bar/filter-bar.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
8 |
9 |
12 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/src/client/filter-bar/filter-bar.styl:
--------------------------------------------------------------------------------
1 | pt-filter-bar
2 | position relative
3 | top 0
4 | height 120px
5 | display block
6 | transition background-color 300ms ease-in
7 |
8 | md-search-autocomplete
9 | position fixed
10 | right 40px
11 | top 40px
12 |
13 | div
14 | padding 20px 76px 20px 70px
15 | -webkit-user-select: none
16 | transition background-color 0.5s
17 | z-index 1
18 |
19 | &.fixed
20 | position fixed
21 | top 0
22 | left 0
23 | right 0
24 | padding-left 170px
25 | margin-top 0
26 | background-color rgba(0, 0, 0, 0.8)
27 |
28 | pt-filter-bar-item
29 | display: inline-block
30 |
31 | md-select
32 | min-width 70px
33 | margin-right 40px
34 | color #fff
35 | border none
36 | font-size 20px
37 | font-weight 600
38 |
39 |
--------------------------------------------------------------------------------
/src/client/gsap/_gsap.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.gsTimelines', []
4 |
--------------------------------------------------------------------------------
/src/client/gsap/directives/gs-pause.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.gsTimelines'
4 |
5 | .directive 'gsPause', ->
6 | restrict: 'E'
7 | scope:
8 | resolve: '&'
9 | position: '@'
10 | require: '^gsTimeline'
11 | link: (scope, element, attr, ctrl) ->
12 | ctrl.addCallback scope.resolve, scope.position
13 | return
14 |
--------------------------------------------------------------------------------
/src/client/gsap/directives/gs-step.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.gsTimelines'
4 |
5 | .directive 'gsStep', ->
6 | restrict: 'E'
7 | scope:
8 | className: '@?'
9 | duration: '@?'
10 | markPosition: '@?'
11 | position: '@?'
12 | style: '@'
13 | require: '^gsTimeline'
14 | compile: (tElement, tAttrs, transclude) ->
15 | if angular.isDefined tAttrs.style
16 | tAttrs.style = tAttrs.style.replace /,/g, ';'
17 |
18 | (scope, element, attr, ctrl) ->
19 | scope.target = attr.target
20 |
21 | scope.$watch 'style', ->
22 | ctrl.addStep scope
23 | return
24 |
25 | return
26 |
--------------------------------------------------------------------------------
/src/client/gsap/services/gs-timeline.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.gsTimelines'
4 |
5 | .directive 'gsTimeline', ($parse, $$gsStates) ->
6 | counter = 1
7 |
8 | restrict: 'E'
9 | scope: timeScale: '@?'
10 | require: '^?gsTimeline'
11 | controller: 'TimeLineController'
12 | link: (scope, element, attr, controller) ->
13 |
14 | prepareResolve = ->
15 | if angular.isDefined(attr.resolve)
16 | context = scope.$parent
17 | fn = $parse(attr['resolve'], null, true)
18 |
19 | controller.addResolve ->
20 | fn context
21 |
22 | return
23 |
24 | prepareStateWatch = ->
25 | if angular.isDefined(attr.state)
26 | $$gsStates.addTimeline
27 | scope: scope
28 | state: attr.state
29 | controller: controller
30 | parentController: element.parent().controller 'gsTimeline'
31 |
32 | return
33 |
34 | scope.id = attr.id or attr.state or 'timeline_' + counter++
35 | scope.position = attr.position or 0
36 | scope.timeScale = scope.timeScale or 1.0
37 | scope.state = attr.state
38 | scope.target = attr.target
39 |
40 | prepareResolve()
41 | prepareStateWatch()
42 |
--------------------------------------------------------------------------------
/src/client/gsap/services/log-build.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.gsTimelines'
4 |
5 | .factory 'logBuild', ($log, gsUtils) ->
6 | { keyValue } = gsUtils
7 |
8 | (source, targets) ->
9 | $log.debug ">> TimelineBuilder::makeTimeline() invoked by $timeline(#{source.timeline.data.id})"
10 |
11 | source.steps.forEach (step) ->
12 | frameLabel = keyValue(step, 'markPosition')
13 | position = keyValue(step, 'position', '')
14 | styles = toJSON(keyValue(step, 'style'))
15 | hasDuration = ! !keyValue(step, 'duration')
16 | duration = if hasDuration then keyValue(step, 'duration') else 0
17 |
18 | if frameLabel
19 | $log.debug "addLabel(#{[frameLabel ]}"
20 | else if hasDuration
21 | $log.debug "timeline.set( #{ step.target }, #{duration}, #{JSON.stringify(styles)}, #{position} )"
22 | else
23 | $log.debug "timeline.set( #{step.target}, #{JSON.stringify(styles)} )"
24 |
25 | return
26 |
27 | source.children.forEach (it) ->
28 | if it.timeline
29 | $log.debug "$timeline(#{source.timeline.data.id}).addChild(#{it.timeline.data.id})"
30 |
31 | source.timeline
--------------------------------------------------------------------------------
/src/client/header/header.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | remote = require 'remote'
4 |
5 | angular.module 'app.header', []
6 |
7 | .directive 'ptHeader', ->
8 | restrict: 'E'
9 | templateUrl: 'header/header.html'
10 | controller: 'ptHeaderCtrl as title'
11 |
12 | .controller 'ptHeaderCtrl', ($scope, $rootScope, titleButtons, AdvSettings, $location) ->
13 | vm = this
14 |
15 | vm.platform = process.platform
16 | vm.buttons = titleButtons[process.platform]
17 | vm.name = AdvSettings.get('branding').name
18 |
19 | vm.max = ->
20 | window = remote.getCurrentWindow()
21 | if window.isFullScreen()
22 | vm.fullscreen()
23 | else
24 | if window.isMaximized()
25 | window.unmaximize()
26 | else
27 | window.maximize()
28 |
29 | vm.min = ->
30 | window = remote.getCurrentWindow()
31 | window.minimize()
32 |
33 | vm.close = ->
34 | window = remote.getCurrentWindow()
35 | window.close()
36 |
37 | vm.fullscreen = ->
38 | window.setFullScreen(vm.state.fullscreen)
39 |
40 | return
41 |
--------------------------------------------------------------------------------
/src/client/header/header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ title.name }}
5 |
6 |
7 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/client/header/header.styl:
--------------------------------------------------------------------------------
1 | pt-header
2 | z-index 15
3 | display block
4 | width 100vw
5 | height 35px
6 | position fixed
7 | margin-top: 10px
8 | padding-bottom: 5px
9 | text-align center
10 | -webkit-app-region: drag
11 |
12 | span
13 | opacity 0.9
14 | font-size 16px
15 | font-weight 500
16 |
17 | .os-controls
18 |
19 | float right
20 | padding-right 20px
21 | z-index 18
22 | -webkit-app-region: no-drag
23 |
24 | md-icon
25 | width 16px
26 | height 16px
27 | margin-left 10px
28 | transition -webkit-filter 200ms ease-out
29 |
30 | &:hover
31 | -webkit-filter grayscale(100%)
32 |
--------------------------------------------------------------------------------
/src/client/page-header/page-header.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.page-header', []
4 |
5 | .directive 'ptPageHeader', ->
6 | restrict: 'E'
7 | templateUrl: 'page-header/page-header.html'
8 | scope: { title: '=', goBack: '&', torrentId: '=?' }
9 | bindToController: true
10 | controller: 'pageHeaderController as header'
11 |
12 | .controller 'pageHeaderController', ->
13 | vm = this
14 |
15 | vm.torrentId = null
16 |
--------------------------------------------------------------------------------
/src/client/page-header/page-header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | arrow_back
4 |
5 |
6 |
7 | {{ header.title }}
8 |
9 |
10 |
11 |
12 | bookmark_outline
13 |
14 |
15 |
16 | visibility_off
17 |
18 |
--------------------------------------------------------------------------------
/src/client/page-header/page-header.styl:
--------------------------------------------------------------------------------
1 | pt-page-header
2 | display block
3 | padding 0px 40px 0 40px
4 | position fixed
5 | z-index 3
6 | height 120px
7 | top 0
8 | left 100px
9 | right 0px
10 |
11 | &.detail
12 | height 12vh
13 | position relative
14 | padding 40px 40px 0 40px
15 | left 0px
16 |
17 | .title
18 | padding-top 0px
19 |
20 | .back
21 | float left
22 | position relative
23 | margin-right 46px !important
24 |
25 | .title
26 | color #FFF
27 | float left
28 | position: relative
29 | line-height 43px
30 | padding-top 40px
31 | font-size 42px
32 | font-weight 500
33 | letter-spacing 0.7
34 |
35 | .right-icon
36 | position relative
37 | float right
38 |
39 | md-icon.material-icons
40 | height 42px
41 | width 42px
42 | color #FFF
43 | line-height 43px
44 | font-size 42px
45 | font-weight 500
46 |
--------------------------------------------------------------------------------
/src/client/play-torrent/play-torrent.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.play-torrent', []
4 |
5 | .directive 'ptPlayTorrent', (torrentProvider) ->
6 | restrict: 'E'
7 | bindToController: { torrentLink: '=', episode: '=', quality: '=' , device: '=', detail: '=' }
8 | scope: { torrent: '=', player: '=' }
9 | templateUrl: 'play-torrent/play-torrent.html'
10 | controller: 'playTorrentController as ctrl'
11 | link: (scope, element, attrs) ->
12 | ctrl = scope.ctrl
13 |
14 | scope.startTorrent = ->
15 | console.log "Starting torrent ..."
16 | scope.player = ctrl
17 |
18 | torrentProvider.addTorrentLink(ctrl.torrentLink).then (resp) ->
19 | torrentProvider.getTorrent(resp.data.infoHash).then (torrentDetail) ->
20 | scope.torrent = torrentDetail
21 | scope.torrent.listen()
22 |
23 | return
24 |
25 | .controller 'playTorrentController', (Settings, torrentProvider) ->
26 | vm = this
27 |
28 | return
29 |
--------------------------------------------------------------------------------
/src/client/play-torrent/play-torrent.html:
--------------------------------------------------------------------------------
1 |
2 | play_arrow
3 | S{{ ctrl.episode.season | padNumber }}E{{ ctrl.episode.episode | padNumber }}
4 |
5 |
--------------------------------------------------------------------------------
/src/client/plugins-manager/app.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.plugins', []
4 |
--------------------------------------------------------------------------------
/src/client/plugins-manager/service/BrowserEngines.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.plugins'
4 |
5 | .factory 'BrowserEngines', ($log, $q, GenericEngine) ->
6 | engines = {}
7 |
8 | registerGenericEngine: (name, factory) ->
9 | @registerEngine name, new GenericEngine factory
10 |
11 | registerEngine: (name, implementation) ->
12 | if name of engines
13 | $log.info 'Updating torrent search engine', name
14 | else
15 | $log.info 'Registering torrent search engine:', name
16 |
17 | engines[name] = implementation
18 |
19 | return
20 |
21 | getSearchEngines: ->
22 | engines
23 |
24 | getSearchEngine: (engine) ->
25 | engines[engine]
26 |
27 | removeSearchEngine: (name) ->
28 | if name of engines
29 | delete engines[name]
30 |
31 | findEpisode: (serie, episode) ->
32 | $log.info serie, episode
33 |
34 | search: (query, TVDB_ID, options) ->
35 | $log.info query, TVDB_ID, options
36 |
--------------------------------------------------------------------------------
/src/client/plugins-manager/service/RequestService.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.plugins'
4 |
5 | .factory 'promiseRequest', ($interpolate, $injector, $http, $q) ->
6 | getUrl = (engine, type, param, param2) ->
7 | engine.base + $interpolate(engine.endpoints[type], query: param)
8 |
9 | getParser = (engine, type) ->
10 | if type of parsers then engine.parsers[type] else (data) ->
11 | data.data
12 |
13 | search: (engine, type, param, param2, promise) ->
14 | torrentEngine = $injector.get engine
15 |
16 | url = getUrl torrentEngine, type, param, param2
17 | parser = getParser torrentEngine, type
18 |
19 | if torrentEngine.activeSearchRequest
20 | @cancelSearch engine
21 |
22 | torrentEngine.activeSearchRequest = $q.defer()
23 |
24 | $http
25 | method: 'GET'
26 | url: url
27 | timeout: if promise then promise else 30000
28 | cache: true
29 | .then (result) ->
30 | torrentEngine.activeSearchRequest.resolve parser(result)
31 |
32 | torrentEngine.activeSearchRequest.promise
33 |
34 | cancelSearch: (engine) ->
35 | { activeSearchRequest } = $injector.get engine
36 |
37 | if activeSearchRequest and activeSearchRequest.resolve
38 | activeSearchRequest.reject 'search abort'
39 | activeSearchRequest = false
40 | activeSearchRequest = $q.defer()
--------------------------------------------------------------------------------
/src/client/providers/cache.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.providers', []
4 |
5 | .factory 'timeoutCache', ($cacheFactory, $timeout) ->
6 | timeouts = {}
7 |
8 | cache = $cacheFactory 'timeoutCache'
9 |
10 | ticktock = (id, lifespan) ->
11 | if timeouts[id]
12 | $timeout.cancel timeouts[id]
13 |
14 | timeouts[id] = $timeout ->
15 | cache.remove id
16 | delete timeouts[id]
17 | , lifespan, false
18 |
19 | (lifespan) ->
20 | get: (id) ->
21 | ticktock id, lifespan
22 | cache.get id
23 |
24 | put: (id, value) ->
25 | ticktock id, lifespan
26 | cache.put id, value
27 |
28 | remove: (id) ->
29 | if timeouts[id]
30 | $timeout.cancel timeouts[id]
31 | delete timeouts[id]
32 | cache.remove id
33 |
34 | removeAll: ->
35 | angular.forEach timeouts, (timeout, id) ->
36 | $timeout.cancel timeout
37 | delete timeouts[id]
38 | cache.removeAll()
39 |
40 | destroy: ->
41 | @removeAll()
42 | cache.destroy()
43 |
--------------------------------------------------------------------------------
/src/client/quality-icon/quality-icon.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.quality-icon', []
4 |
5 | .directive 'qualityIcon', ->
6 | restrict: 'A'
7 | scope: { torrent: '=' }
8 | bindToController: true
9 | templateUrl: 'quality-icon/quality-icon.html'
10 | controller: 'qualityIconCtrl as quality'
11 |
12 | .controller 'qualityIconCtrl', (torrentHealth, $filter, $scope) ->
13 | vm = this
14 |
15 | torrentHealthRestarted = 0
16 |
17 | onSuccess = (torrent) ->
18 | vm.health = $filter('calcHealth')(torrent)
19 | vm.ratio = if torrent.peers > 0 then torrent.seeds / torrent.peers else +torrent.seeds
20 |
21 | onError = -> vm.health = 'none'
22 |
23 | vm.getTorrentHealth = (newTorrent) ->
24 | vm.health = null
25 |
26 | if newTorrent.substring(0, 8) is 'magnet:?'
27 | torrentLink = newTorrent.split('&tr')[0] + '&tr=udp://tracker.openbittorrent.com:80/announce' + '&tr=udp://open.demonii.com:1337/announce' + '&tr=udp://tracker.coppersurfer.tk:6969'
28 |
29 | torrentHealth(torrentLink).then onSuccess, onError
30 |
31 | $scope.$watch 'quality.torrent', (newTorrent) ->
32 | vm.getTorrentHealth newTorrent.url
33 |
34 | return
--------------------------------------------------------------------------------
/src/client/quality-icon/quality-icon.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/client/quality-selector/quality-selector.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.quality-selector', []
4 |
5 | .directive 'ptQualitySelector', ->
6 | scope: { torrents: '=', selected: '=' }
7 | bindToController: { list: '=' }
8 | templateUrl: 'quality-selector/quality-selector.html'
9 | controller: 'qualityCtrl as quality'
10 |
11 | .controller 'qualityCtrl', ($scope) ->
12 | vm = this
13 |
14 | # If no selection or selection is not in the list: get first element in the list
15 | for key of vm.list
16 | vm.selected = key unless vm.selected and vm.list.indexOf(vm.selected) isnt -1
17 | break
18 |
19 | vm.openMenu = ($mdOpenMenu, event) ->
20 | originatorEv = event
21 | $mdOpenMenu event
22 |
23 | vm.setItem = (quality) ->
24 | vm.selected = quality
25 |
26 | vm.setItem vm.selected
27 |
28 | return
29 |
--------------------------------------------------------------------------------
/src/client/quality-selector/quality-selector.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 | {{ quality.selected }}
7 |
8 |
9 |
10 |
11 |
12 | {{ q }}
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/client/quality-selector/quality-selector.styl:
--------------------------------------------------------------------------------
1 | md-menu.quality-selector
2 |
3 | .md-button
4 |
5 | transition opacity 400ms ease-out
6 | text-transform none
7 |
8 | &:hover
9 | opacity 0.4
10 |
--------------------------------------------------------------------------------
/src/client/services/cloudflare-api.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.services'
4 |
5 | .factory 'cloudFlareApi', ($q, request, timeoutCache)->
6 |
7 | cache = timeoutCache 10 * 60 * 1000
8 |
9 | (url, params) ->
10 | defer = $q.defer()
11 |
12 | cachedData = cache.get url + JSON.stringify params
13 |
14 | if cachedData
15 | defer.resolve cachedData
16 | else
17 | request
18 | uri: url
19 | qs: params
20 | headers:
21 | 'Host': 'xor.image.yt'
22 | 'User-Agent': 'Mozilla/5.0 (Linux) AppleWebkit/534.30 (KHTML, like Gecko) PT/3.8.0'
23 | strictSSL: false
24 | json: true
25 | timeout: 10000
26 | , (err, res, data) ->
27 | if err or res.statusCode >= 400
28 | defer.reject err
29 | else
30 | cache.put url + JSON.stringify params, data
31 | defer.resolve data
32 |
33 | defer.promise
34 |
--------------------------------------------------------------------------------
/src/client/services/collapse.coffee:
--------------------------------------------------------------------------------
1 | angular.module 'app.services'
2 |
3 | .factory '$mdCollapse', ($animateCss) ->
4 |
5 | expand: (element) ->
6 |
7 | expandDone = ->
8 | element
9 | .removeClass 'collapsing'
10 | .addClass 'collapse'
11 | .css height: 'auto'
12 |
13 | return
14 |
15 | element
16 | .removeClass 'collapse'
17 | .addClass 'collapsing'
18 | .attr 'aria-expanded', true
19 | .attr 'aria-hidden', false
20 |
21 | $animateCss element,
22 | addClass: 'in'
23 | easing: 'ease'
24 | to: height: element[0].scrollHeight + 'px'
25 | .start()
26 | .done expandDone
27 |
28 | return
29 |
30 | collapse: (element) ->
31 |
32 | collapseDone = ->
33 | element
34 | .css height: '0'
35 | .removeClass 'collapsing'
36 | .addClass 'collapse'
37 |
38 | return
39 |
40 | element
41 | .css height: element[0].scrollHeight + 'px'
42 | .removeClass 'collapse'
43 | .addClass 'collapsing'
44 | .attr 'aria-expanded', false
45 | .attr 'aria-hidden', true
46 |
47 | $animateCss element,
48 | removeClass: 'in'
49 | to: height: '0px'
50 | .start()
51 | .done collapseDone
52 |
53 | return
54 |
--------------------------------------------------------------------------------
/src/client/services/keep-awake.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.services'
4 |
5 | .factory 'keepAwake', ->
6 | video = null
7 |
8 | stop = ->
9 | if video isnt null
10 | video.pause()
11 | video.src = ''
12 |
13 | start: ->
14 | if video is null
15 | video = document.createElement 'video'
16 |
17 | document.body.appendChild video
18 |
19 | video.id = 'keep-awake-video'
20 | video.src = 'data:video/webm;base64,GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA='
21 | video.loop = true
22 |
23 | video.play()
--------------------------------------------------------------------------------
/src/client/services/node-helpers.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.services'
4 |
5 | .constant 'Datastore', require 'nedb'
6 |
7 | .constant 'tls', require 'tls'
8 | .constant 'url', require 'url'
9 | .constant 'ipc', require 'ipc'
10 | .constant 'os', require 'os'
11 |
12 | .constant 'request', require 'request'
13 | .constant 'torrenthealth', require 'torrent-health'
14 |
15 | .constant 'data_path', 'test'
16 |
17 | .constant 'nodeFs', require 'fs'
18 | .constant 'path', require 'path'
19 |
20 | .factory 'tvdb', (Settings) ->
21 | tvdbClient = require 'node-tvdb'
22 |
23 | new tvdbClient('7B95D15E1BE1D75A', Settings.language)
24 |
--------------------------------------------------------------------------------
/src/client/services/player-service.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.services'
4 |
5 | .factory 'playerService', ($q) ->
6 | findTorrentUrl = (episode, selected, defaultQuality) ->
7 | if defaultQuality isnt '0'
8 | quality = episode.torrents[defaultQuality]
9 | if quality then return torrent.url
10 | episode.torrents[0].url
11 |
12 | sortNextEpisodes: (player) ->
13 | return $q.reject() unless player?.detail
14 |
15 | show = player.detail
16 |
17 | selected = player.episode
18 | defaultQuality = player.quality
19 |
20 | playNextEpisodes = []
21 |
22 | for episode in show.episodes
23 | if (episode.episode >= selected.episode and episode.season is selected.season) or (episode.season > selected.season)
24 | playNextEpisodes.push
25 | title: episode.title
26 | season: episode.season
27 | episode: episode.episode
28 | torrent: findTorrentUrl episode, selected, defaultQuality
29 |
30 | $q.when playNextEpisodes
31 |
--------------------------------------------------------------------------------
/src/client/services/torrent-health.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.services'
4 |
5 | .factory 'torrentHealth', ($q, torrenthealth) ->
6 | (torrentLink) ->
7 | defer = $q.defer()
8 |
9 | torrentHealthRestarted = 0
10 |
11 | getTorrent = ->
12 | torrenthealth(torrentLink, timeout: 1000).then (torrent) ->
13 | if torrent.seeds is 0 and torrentHealthRestarted < 5
14 | torrentHealthRestarted++
15 | getTorrent()
16 | else if torrent.seeds isnt 0
17 | defer.resolve torrent
18 | else defer.reject()
19 |
20 | getTorrent()
21 |
22 | defer.promise
23 |
--------------------------------------------------------------------------------
/src/client/services/xml.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.services'
4 |
5 | .config ($httpProvider) ->
6 | $httpProvider.interceptors.push 'xmlHttpInterceptor'
7 |
8 | .factory 'xmlHttpInterceptor', ($q, xmlFilter) ->
9 | response: (data) ->
10 | if data
11 | data.xml = xmlFilter(data.data)
12 | data
13 | else $q.when data
14 |
15 | .factory 'xmlParser', ($window) ->
16 |
17 | ActiveXObject = ->
18 | @parser = new ($window.ActiveXObject)('Microsoft.XMLDOM')
19 | return
20 |
21 | ActiveXObject::parse = (data) ->
22 | @parser.async = false
23 | @parser.loadXml data
24 |
25 | DOMParser = ->
26 | @parser = new ($window.DOMParser)
27 | return
28 |
29 | DOMParser::parse = (data) ->
30 | @parser.parseFromString data, 'text/xml'
31 |
32 | if $window.DOMParser
33 | return new DOMParser
34 |
35 | if $window.ActiveXObject
36 | return new ActiveXObject
37 |
38 | throw Error 'Cannot parser XML in this environment.'
39 |
40 | .filter 'xml', (xmlParser) ->
41 | (input) ->
42 | parsedInput = xmlParser.parse input
43 | angular.element parsedInput
44 |
--------------------------------------------------------------------------------
/src/client/settings/templates/settings-buttons.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/client/settings/templates/settings-cache.html:
--------------------------------------------------------------------------------
1 |
23 |
--------------------------------------------------------------------------------
/src/client/settings/templates/settings-database.html:
--------------------------------------------------------------------------------
1 |
29 |
--------------------------------------------------------------------------------
/src/client/settings/templates/settings-features.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 | Torrent Collection
10 |
11 |
12 |
13 |
14 |
15 | Watchlist
16 |
17 |
18 |
19 |
20 |
21 | vpn_key
22 | VPN
23 |
24 |
25 |
26 |
27 |
28 | swap_calls
29 | Randomize Button for Movies
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/client/settings/templates/settings-playback.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 | Always start playing in fullscreen
10 |
11 |
12 |
13 |
14 |
15 | Play next episode automatically
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/client/settings/templates/settings-quality.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | Only list movies in
9 |
11 |
13 | {{ value }}
14 |
15 |
16 |
17 |
18 |
19 |
20 | Show movie quality on list
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/client/settings/templates/settings-title.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 | keyboard
10 | Keyboard Shortcuts
11 |
12 |
13 |
14 | question
15 |
16 |
17 |
18 | Show advanced settings
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/client/settings/templates/settings-tvshowtime.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
19 |
20 | user
21 | Connect To TVShow Time
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/client/sidebar/sidebar.styl:
--------------------------------------------------------------------------------
1 | pt-content
2 | transition margin-left 0.2s ease-out
3 |
4 | pt-page-header .title
5 | transition margin-left 0.2s ease-out
6 |
7 | pt-sidebar
8 | max-width 100px
9 | min-width 0px
10 | z-index 9
11 | overflow visible
12 | user-select none
13 | height 100%
14 |
15 | &:hover
16 | nav
17 | width 180px !important
18 |
19 | .md-button span
20 | opacity 1
21 |
22 | &:hover ~ pt-content
23 | margin-left 80px
24 |
25 | nav
26 | padding-top 50px
27 | transition width 0.2s ease-out, left 0.5s ease-out
28 | min-width 60px !important
29 | width 60px !important
30 | max-width 180px !important
31 | height inherit
32 | background-color inherit
33 |
34 | .md-button
35 | cursor pointer
36 | line-height 60px
37 | padding 0px 0px 0px 10px
38 | max-height 60px
39 | text-transform none
40 | min-width 0px
41 | overflow hidden
42 | margin 0
43 | text-align left
44 | width 100%
45 |
46 | span
47 | opacity 0
48 | margin-left 10px
49 | transition opacity 0.3s ease-in
50 |
51 | span, md-icon
52 | padding 0px 5px 10px
53 |
54 | .md-button .md-ripple-container
55 | border-radius 0px !important
56 |
57 | button.md-button-moz-focus-inner
58 | padding 0
59 |
--------------------------------------------------------------------------------
/src/client/streamer/socket.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.streamer'
4 |
5 | .provider 'serverPort', ->
6 | port = null
7 |
8 | setPort: (newport) ->
9 | port = newport
10 |
11 | $get: -> port
12 |
13 | .config (serverPortProvider) ->
14 | ipc = require 'ipc'
15 |
16 | port = ipc.sendSync 'get-port', null
17 |
18 | serverPortProvider.setPort port
19 |
20 | .run (socketServer, torrentProvider) ->
21 | socketServer.start().then ->
22 | torrentProvider.getAllTorrents()
23 |
24 | .factory 'socketServer', (socketFactory, $q, serverPort) ->
25 | connection: null
26 |
27 | start: ->
28 | if not @connection
29 | @connection = socketFactory ioSocket: io "http://127.0.0.1:#{serverPort}/"
30 | $q.when()
--------------------------------------------------------------------------------
/src/client/torrents/torrents.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.torrents', []
4 |
5 | .directive 'ptTorrentItem', ->
6 | restrict: 'E'
7 | scope: { data: '=' }
8 | controllerAs: 'torrent'
9 | bindToController: true
10 | templateUrl: 'torrents/torrents.html'
11 | controller: ($scope, torrentProvider, socketServer) ->
12 | vm = this
13 |
14 | vm.download = ->
15 | if vm.link
16 | Torrent.save(link: vm.link).$promise.then (torrent) ->
17 | loadTorrent torrent.infoHash
18 | vm.link = ''
19 |
20 | vm.pause = (torrent, $event) ->
21 | $event.stopPropagation()
22 | socketServer.emit (if torrent.stats.paused then 'resume' else 'pause'), torrent.infoHash
23 |
24 | vm.remove = (torrent) ->
25 | Torrent.remove infoHash: torrent.infoHash
26 | delete vm.data[torrent.infoHash]
27 |
28 | return
29 |
30 | .controller 'torrentsController', ($interval, $resource, $q, socketServer, streamServer, torrentProvider) ->
31 | vm = this
32 |
33 | vm.keypress = (e) ->
34 | if e.which == 13
35 | vm.download()
36 | return
37 |
38 | vm.select = (torrent, file) ->
39 | socketServer.emit (if file.selected then 'deselect' else 'select'), torrent.infoHash, torrent.files.indexOf(file)
40 |
41 | return
42 |
43 |
--------------------------------------------------------------------------------
/src/client/torrents/torrents.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Torrents
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-bottom-controls/wc-fullscreen-button/wc-fullscreen-button.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.controls'
4 |
5 | .directive 'wcFullscreenButton', ->
6 | restrict: 'E'
7 | require: '^chimerangular'
8 | scope: {}
9 | templateUrl: 'webchimera/views/directives/wc-fullscreen-button.html'
10 | link: (scope, elem, attr, chimera) ->
11 |
12 | scope.onChangeFullScreen = (isFullScreen) ->
13 | if isFullScreen
14 | scope.fullscreenIcon = 'fullscreen_exit'
15 | else scope.fullscreenIcon = 'fullscreen'
16 |
17 | scope.onClickFullScreen = ->
18 | chimera.toggleFullScreen()
19 |
20 | scope.fullscreenIcon = 'fullscreen'
21 |
22 | scope.$watch ->
23 | chimera.isFullScreen
24 | , (newVal, oldVal) ->
25 | if newVal != oldVal
26 | scope.onChangeFullScreen newVal
27 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-bottom-controls/wc-play-pause-button/wc-play-pause-button.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.controls'
4 |
5 | .directive 'wcPlayPauseButton', (WC_STATES) ->
6 | restrict: 'E'
7 | require: '^chimerangular'
8 | scope: {}
9 | templateUrl: 'webchimera/views/directives/wc-play-pause-button.html'
10 | link: (scope, elem, attr, chimera) ->
11 |
12 | scope.setState = (newState) ->
13 | switch newState
14 | when WC_STATES.PLAY
15 | scope.playPauseIcon = 'pause'
16 | when WC_STATES.PAUSE, WC_STATES.STOP
17 | scope.playPauseIcon = 'play_arrow'
18 |
19 | scope.onClickPlayPause = ->
20 | chimera.playPause()
21 |
22 | scope.playPauseIcon = 'play_arrow'
23 |
24 | scope.$watch ->
25 | chimera.currentState
26 | , (newVal, oldVal) ->
27 | scope.setState newVal
28 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-bottom-controls/wc-playback-button/wc-playback-button.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.controls'
4 |
5 | .directive 'wcPlaybackButton', (WC_UTILS) ->
6 | restrict: 'E'
7 | require: '^chimerangular'
8 | templateUrl: 'webchimera/views/directives/wc-playback-button.html'
9 | link: (scope, elem, attr, chimera) ->
10 | scope.playback = '1.0'
11 |
12 | scope.onClickPlayback = ->
13 | playbackOptions = ['.5', '1.0', '1.5', '2.0']
14 |
15 | nextPlaybackRate = playbackOptions.indexOf(scope.playback) + 1
16 |
17 | if nextPlaybackRate >= playbackOptions.length
18 | scope.playback = playbackOptions[0]
19 | else
20 | scope.playback = playbackOptions[nextPlaybackRate]
21 |
22 | chimera.setPlayback scope.playback
23 |
24 | scope.$watch ->
25 | chimera.playback
26 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-bottom-controls/wc-scrub-bar/wc-scrub-bar-current-time.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.controls'
4 |
5 | .directive 'wcScrubBarCurrentTime', ->
6 | restrict: 'E'
7 | require: '^chimerangular'
8 | link: (scope, elem, attr, chimera) ->
9 | percentTime = 0
10 |
11 | scope.onUpdateTime = (newCurrentTime) ->
12 | if typeof newCurrentTime == 'number' and chimera.totalTime
13 | percentTime = 100 * (newCurrentTime / chimera.totalTime)
14 | elem.css 'width', percentTime + '%'
15 | else elem.css 'width', 0
16 |
17 | scope.$watch ->
18 | chimera.currentTime
19 | , (newVal, oldVal) ->
20 | scope.onUpdateTime newVal
21 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-bottom-controls/wc-subtitle/wc-subtitle.styl:
--------------------------------------------------------------------------------
1 | wc-subtitle
2 | display: table-cell
3 | width: 50px
4 | vertical-align: middle
5 | text-align: center
6 | cursor: pointer
7 | color: white
8 | font-size: 14px
9 |
10 | button
11 | display: block
12 |
13 | wc-subtitle-selector ul
14 | width: 50px
15 | bottom: 50px
16 | margin: 0
17 | padding-left: 0
18 | vertical-align: middle
19 | text-align: center
20 | position: absolute
21 | cursor: pointer
22 | list-style: none
23 |
24 | li
25 | line-height: 16px
26 | padding: 5px
27 | opacity: 0.7
28 | background-color: #222222
29 | margin: 1px 0
30 |
31 | &:hover
32 | opacity: 1
33 |
34 | ul li.active
35 | background-color: #333333
36 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-bottom-controls/wc-time-display/wc-time-display.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.controls'
4 |
5 | .directive 'wcTimeDisplay', ->
6 | require: '^chimerangular'
7 | restrict: 'E'
8 | link: (scope, elem, attr, chimera) ->
9 | scope.currentTime = chimera.currentTime
10 | scope.timeLeft = chimera.timeLeft
11 | scope.totalTime = chimera.totalTime
12 | scope.isLive = chimera.isLive
13 |
14 | scope.$watch ->
15 | chimera.currentTime
16 | , (newVal, oldVal) ->
17 | scope.currentTime = newVal
18 |
19 | scope.$watch ->
20 | chimera.timeLeft
21 | , (newVal, oldVal) ->
22 | scope.timeLeft = newVal
23 |
24 | scope.$watch ->
25 | chimera.totalTime
26 | , (newVal, oldVal) ->
27 | scope.totalTime = newVal
28 |
29 | scope.$watch ->
30 | chimera.isLive
31 | , (newVal, oldVal) ->
32 | scope.isLive = newVal
33 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-bottom-controls/wc-volume/wc-volume.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.controls'
4 |
5 | .directive 'wcVolume', (WC_UTILS) ->
6 | restrict: 'E'
7 | link: (scope, elem, attr) ->
8 |
9 | scope.onMouseOverVolume = ->
10 | scope.$evalAsync ->
11 | scope.volumeVisibility = 'visible'
12 |
13 | scope.onMouseLeaveVolume = ->
14 | scope.$evalAsync ->
15 | scope.volumeVisibility = 'hidden'
16 |
17 | scope.volumeVisibility = 'hidden'
18 | elem.bind 'mouseover', scope.onMouseOverVolume
19 | elem.bind 'mouseleave', scope.onMouseLeaveVolume
20 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-buffering/wc-buffering.styl:
--------------------------------------------------------------------------------
1 | /********************/
2 | /* Buffering plugin */
3 | /********************/
4 | wc-buffering
5 | width: 100%
6 | height: 100%
7 | position: absolute
8 | z-index: 4
9 | top: 0
10 |
11 | wc-buffering .bufferingContainer
12 | width: 100%
13 | position: absolute
14 | cursor: pointer
15 | top: 50%
16 | margin-top: -50px
17 | zoom: 1
18 | opacity: 0.6
19 |
20 | wc-buffering .loadingSpinner
21 | background-color: rgba(0, 0, 0, 0)
22 | border: 5px solid rgba(255, 255, 255, 1)
23 | opacity: .9
24 | border-top: 5px solid rgba(0, 0, 0, 0)
25 | border-left: 5px solid rgba(0, 0, 0, 0)
26 | border-radius: 50px
27 | box-shadow: 0 0 35px #FFFFFF
28 | width: 50px
29 | height: 50px
30 | margin: 0 auto
31 | -moz-animation: spin .5s infinite linear
32 | -webkit-animation: spin .5s infinite linear
33 |
34 | wc-buffering .loadingSpinner .stop
35 | -webkit-animation-play-state: paused
36 | -moz-animation-play-state: paused
37 |
38 | @keyframes spin {
39 | 0% {
40 | -webkit-transform: rotate(0deg)
41 | }
42 | 100% {
43 | -webkit-transform: rotate(360deg)
44 | }
45 | }
46 |
47 | @keyframes spinoff {
48 | 0% {
49 | -webkit-transform: rotate(0deg)
50 | }
51 | 100% {
52 | -webkit-transform: rotate(-360deg)
53 | }
54 | }
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-dash/wc-dash.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.dash', []
4 |
5 | .directive 'wcDash', ->
6 | restrict: 'A'
7 | require: '^chimerangular'
8 | link: (scope, elem, attr, chimera) ->
9 | context = undefined
10 | player = undefined
11 |
12 | scope.isDASH = (url) ->
13 | if url.indexOf
14 | return url.indexOf('.mpd') > 0
15 |
16 | scope.onSourceChange = (url) ->
17 | # It's DASH, we use Dash.js
18 | if scope.isDASH(url)
19 | context = new (Dash.di.DashContext)
20 | player = new MediaPlayer(context)
21 | player.setAutoPlay chimera.autoPlay
22 | player.startup()
23 | player.attachView chimera.wcjsElement
24 | player.attachSource url
25 | else
26 | if player
27 | player.reset()
28 | player = null
29 |
30 | scope.$watch ->
31 | chimera.sources
32 | , (newVal, oldVal) ->
33 | scope.onSourceChange newVal[0].src
34 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-ima-ads/wc-ima-ads.styl:
--------------------------------------------------------------------------------
1 | /**********************/
2 | /* IMA ads plugin */
3 | /**********************/
4 | wc-ima-ads
5 | width: 100vw
6 | height: 100vh
7 | position: absolute
8 | z-index: 5
9 | top: 0
10 | display: none
11 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-overlay-play/wc-overlay-play.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.overlayplay', []
4 |
5 | .directive 'wcOverlayPlay', (WC_STATES) ->
6 | restrict: 'E'
7 | require: '^chimerangular'
8 | scope: {}
9 | templateUrl: 'webchimera/views/directives/wc-overlay-play.html'
10 | link: (scope, elem, attr, chimera) ->
11 | scope.chimera = chimera
12 |
13 | scope.onChangeState = (newState) ->
14 | switch newState
15 | when WC_STATES.PLAY
16 | scope.overlayPlayIcon = false
17 | when WC_STATES.PAUSE
18 | scope.overlayPlayIcon = true
19 | when WC_STATES.STOP
20 | scope.overlayPlayIcon = true
21 |
22 | scope.onClickOverlayPlay = (event) ->
23 | chimera.playPause()
24 |
25 | scope.overlayPlayIcon = false
26 |
27 | scope.$watch ->
28 | chimera.currentState
29 | , (newVal, oldVal) ->
30 | scope.onChangeState newVal
31 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-overlay-play/wc-overlay-play.styl:
--------------------------------------------------------------------------------
1 | /**********************/
2 | /* OverlayPlay plugin */
3 | /**********************/
4 |
5 | wc-overlay-play
6 | width: 100%
7 | height: 100%
8 | max-width: 100%
9 | max-height: 100%
10 | position: absolute
11 | z-index: 2
12 | top: 0
13 |
14 | wc-overlay-play .play:before
15 | content: "\e000"
16 |
17 | wc-overlay-play .overlayPlayContainer
18 | font-size: 100px
19 | width: 100%
20 | height: 100%
21 | max-width: 100%
22 | max-height: 100%
23 | position: absolute
24 | display: table
25 | cursor: pointer
26 | zoom: 1
27 | opacity: 0.6
28 |
29 | wc-overlay-play .overlayPlayContainer div
30 | vertical-align: middle
31 | text-align: center
32 | display: table-cell
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-poster/wc-poster.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.poster', []
4 |
5 | .directive 'wcPoster', ->
6 | restrict: 'E'
7 | require: '^chimerangular'
8 | scope: { poster: '=?' }
9 | templateUrl: 'webchimera/views/directives/wc-poster.html'
10 | link: (scope, elem, attr, chimera) ->
11 | scope.chimera = chimera
12 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-poster/wc-poster.styl:
--------------------------------------------------------------------------------
1 | /*****************/
2 | /* Poster plugin */
3 | /*****************/
4 | wc-poster
5 | width: 100%
6 | height: 100%
7 | max-width: 100%
8 | max-height: 100%
9 | position: absolute
10 | display: block
11 | top: 0
12 | pointer-events: none
13 |
14 | wc-poster img
15 | max-width: 100%
16 | max-height: 100%
17 | top: 0
18 | bottom: 0
19 | right: 0
20 | left: 0
21 | margin: auto
22 | position: absolute
23 | height 100vh
24 | width 100vwo
25 | opacity 0
26 | background-size cover
27 | pointer-events: none
28 | -webkit-filter brightness(45%)
29 | transition opacity 200ms ease-in
30 |
31 | &.fadein
32 | opacity: 1
33 |
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-top-controls/wc-close-button/wc-close-button.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.top-controls'
4 |
5 | .directive 'wcCloseButton', ->
6 | restrict: 'E'
7 | require: '^chimerangular'
8 | templateUrl: 'webchimera/views/directives/wc-close-button.html'
9 | link: (scope, elem, attr, chimera) ->
10 | scope.onClosePlayer = ->
11 | chimera.stop()
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-top-controls/wc-top-controls.styl:
--------------------------------------------------------------------------------
1 | /*********************/
2 | /* Controlbar plugin */
3 | /*********************/
4 | wc-top-controls
5 | width: 100%
6 | height: 50px
7 | display: block
8 | position: absolute
9 | z-index: 3
10 | bottom: 0
11 |
12 | wc-top-controls .controls-container
13 | width: 100%
14 | height: 50px
15 | background-color: rgba(0, 0, 0, 0.5)
16 | position: absolute
17 | display: table
18 |
19 | zoom: 1
20 |
21 | wc-close-button
22 | display: table-cell
23 | width: 50px
24 | height: 50px
25 | vertical-align: middle
26 | text-align: center
27 | cursor: pointer
28 | float: left
29 |
30 | wc-top-controls .hide-animation
31 | animation: hideControlsAnimationFrames ease-out 0.5s
32 | animation-iteration-count: 1
33 | animation-fill-mode: forwards /*when the spec is finished*/
34 | -webkit-animation: hideControlsAnimationFrames ease-out 0.5s
35 | -webkit-animation-iteration-count: 1
36 | -webkit-animation-fill-mode: forwards /*Chrome 16+, Safari 4+*/
--------------------------------------------------------------------------------
/src/client/webchimera/_plugins/wc-torrent-info/wc-torrent-info.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera.plugins.torrent-info', []
4 |
5 | .directive 'wcTorrentInfo', ->
6 | restrict: 'E'
7 | require: '^chimerangular'
8 | scope: { torrent: '=?wcTorrent', player: '=?wcPlayer' }
9 | templateUrl: 'webchimera/views/directives/wc-torrent-info.html'
10 | link: (scope, elem, attr, chimera) ->
11 |
12 | scope.stopPlaying = ->
13 | chimera.stop()
14 |
--------------------------------------------------------------------------------
/src/client/webchimera/_webchimera.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera', [
4 | 'app.webchimera.plugins.controls'
5 | 'app.webchimera.plugins.top-controls'
6 | 'app.webchimera.plugins.buffering'
7 | 'app.webchimera.plugins.overlayplay'
8 | 'app.webchimera.plugins.poster'
9 | 'app.webchimera.plugins.torrent-info'
10 | ]
11 |
12 | .directive 'ptDetail', ->
13 | restrict: 'E'
14 | templateUrl: 'webchimera/webchimera.html'
15 | controller: 'detailCtrl as chimera'
16 |
17 | .controller 'detailCtrl', (playerService, $scope, playerConfig, $rootScope) ->
18 | vm = this
19 |
20 | vm.config = playerConfig.config
21 |
22 | vm.player =
23 | id: null
24 |
25 | $scope.$watch 'chimera.torrent.ready', (readyState) ->
26 | vm.config.controls = readyState
27 |
28 | $scope.$watchCollection 'chimera.player', (newPlayer, oldPlayer) ->
29 | if $rootScope.type is 'show'
30 | playerService.sortNextEpisodes(newPlayer).then (data) ->
31 | vm.config.next = data
32 |
33 | return
--------------------------------------------------------------------------------
/src/client/webchimera/directives/chimerangular.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera'
4 |
5 | .directive 'chimerangular', ->
6 | restrict: 'EA'
7 | scope:
8 | wcAutoPlay: '=?'
9 | wcPlaysInline: '=?'
10 | wcCuePoints: '=?'
11 | wcConfig: '=?'
12 | wcCanPlay: '&'
13 | wcComplete: '&'
14 | wcUpdateVolume: '&'
15 | wcUpdatePlayback: '&'
16 | wcUpdateTime: '&'
17 | wcUpdateState: '&'
18 | wcPlayerReady: '&'
19 | wcStop: '&'
20 | wcChangeSource: '&'
21 | wcError: '&'
22 | controller: 'wcController'
23 | controllerAs: 'chimera'
24 | link:
25 | pre: (scope, elem, attr, controller) ->
26 | controller.chimerangularElement = angular.element elem
27 |
--------------------------------------------------------------------------------
/src/client/webchimera/directives/chimerangular.styl:
--------------------------------------------------------------------------------
1 | pt-detail
2 | position: absolute
3 | top: 0
4 | bottom: 0
5 | left: 0
6 | right: 0
7 | z-index: 9
8 |
9 | chimerangular, [chimerangular]
10 | width: 100%
11 | height: 100%
12 | position: relative
13 | background-color: #000000
14 | display: block
15 | flex-direction: column
16 | -webkit-touch-callout: none
17 | -webkit-user-select: none
18 | user-select: none
19 |
20 | button
21 | cursor: pointer
22 |
23 | &.fullscreen
24 | position: fixed
25 | left: 0
26 | top: 0
27 |
28 | wc-media
29 | width: 100%
30 | height: 100%
31 | max-width: 100%
32 | max-height: 100%
33 |
34 | display: block
35 |
36 | canvas
37 | width: 100%
38 | height: 100%
39 | max-width: 100%
40 | max-height: 100%
41 |
42 | .iconButton
43 | color: #FFFFFF
44 | font-family: 'videogular'
45 | speak: none
46 | font-style: normal
47 | font-weight: normal
48 | font-variant: normal
49 | text-transform: none
50 | line-height: 1
51 | -webkit-font-smoothing: antialiased
52 | background: none
53 | padding: 6px
54 | border: none
55 |
56 | .iconButton:focus
57 | border: 1px solid white
--------------------------------------------------------------------------------
/src/client/webchimera/directives/wc-loop.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera'
4 |
5 | .directive 'wcLoop', ->
6 | restrict: 'A'
7 | require: '^chimerangular'
8 | link:
9 | pre: (scope, elem, attr, chimera) ->
10 | lp = undefined
11 |
12 | scope.setLoop = (value) ->
13 | angular.noop()
14 |
15 | if chimera.isConfig
16 | scope.$watch ->
17 | chimera.config
18 | , ->
19 | if chimera.config
20 | scope.setLoop chimera.config.loop
21 | else
22 | scope.$watch attr.wcLoop, (newValue, oldValue) ->
23 | if (!lp or newValue != oldValue) and newValue
24 | lp = newValue
25 | scope.setLoop lp
26 | else scope.setLoop()
27 |
--------------------------------------------------------------------------------
/src/client/webchimera/directives/wc-native-controls.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera'
4 |
5 | .directive 'wcNativeControls', ->
6 | restrict: 'A'
7 | require: '^chimerangular'
8 | link:
9 | pre: (scope, elem, attr, chimera) ->
10 | controls = undefined
11 |
12 | scope.setControls = (value) ->
13 | angular.noop()
14 |
15 | if chimera.isConfig
16 | scope.$watch ->
17 | chimera.config
18 | , ->
19 | if chimera.config
20 | scope.setControls chimera.config.controls
21 | else
22 | scope.$watch attr.wcNativeControls, (newValue, oldValue) ->
23 | if (!controls or newValue != oldValue) and newValue
24 | controls = newValue
25 | scope.setControls controls
26 | else scope.setControls()
27 |
--------------------------------------------------------------------------------
/src/client/webchimera/directives/wc-next-video.styl:
--------------------------------------------------------------------------------
1 | wc-next-video
2 | width: 100vw
3 | height: 100vh
4 | margin: 0
5 | padding: 0
6 | top: 0
7 | left: 0
8 | display: block
9 | position: absolute
10 | z-index: 2
11 |
12 | .loader-container
13 | width: 100vw
14 | height: 100vh
15 | position: absolute
16 | display: flex
17 |
18 | svg.round-progress
19 | margin: auto
20 |
21 | .cancel
22 | color: white
23 | font-family: sans-serif
24 | font-size: 18px
25 | width: 100vw
26 | height: 30px
27 | position: absolute
28 | left: 0
29 | bottom: 50px
30 | text-align: center
31 | cursor: pointer
--------------------------------------------------------------------------------
/src/client/webchimera/directives/wc-preload.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera'
4 |
5 | .directive 'wcPreload', ->
6 | restrict: 'A'
7 | require: '^chimerangular'
8 | link:
9 | pre: (scope, elem, attr, chimera) ->
10 | preload = undefined
11 |
12 | scope.setPreload = (value) ->
13 | angular.noop()
14 |
15 | if chimera.isConfig
16 | scope.$watch ->
17 | chimera.config
18 | , ->
19 | if chimera.config
20 | scope.setPreload chimera.config.preload
21 | else
22 | scope.$watch attr.wcPreload, (newValue, oldValue) ->
23 | if (!preload or newValue != oldValue) and newValue
24 | preload = newValue
25 | scope.setPreload preload
26 | else scope.setPreload()
27 |
--------------------------------------------------------------------------------
/src/client/webchimera/services/wc-config-loader.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera'
4 |
5 | .service 'wcConfigLoader', ($http, $q, $sce) ->
6 |
7 | @loadConfig = (url) ->
8 | deferred = $q.defer()
9 |
10 | $http.get url
11 | method: 'GET'
12 | url: url
13 | .success (response) ->
14 | result = response.data
15 | i = 0
16 | l = result.sources.length
17 |
18 | while i < l
19 | result.sources[i].src = $sce.trustAsResourceUrl result.sources[i].src
20 | i++
21 |
22 | deferred.resolve result
23 | .error -> deferred.reject()
24 |
25 | deferred.promise
26 |
27 | return
28 |
--------------------------------------------------------------------------------
/src/client/webchimera/services/wc-fullscreen-api.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera'
4 |
5 | .service 'wcFullscreen', (WC_UTILS, WC_FULLSCREEN_APIS) ->
6 | # Native fullscreen polyfill
7 | polyfill = null
8 |
9 | APIS = WC_FULLSCREEN_APIS
10 |
11 | isFullScreen = ->
12 | document[polyfill.element] != null
13 |
14 | for browser of APIS
15 | if APIS[browser].enabled of document
16 | polyfill = APIS[browser]
17 | break
18 |
19 | @isAvailable = polyfill != null
20 |
21 | if polyfill
22 | @onchange = polyfill.onchange
23 | @onerror = polyfill.onerror
24 | @isFullScreen = isFullScreen
25 |
26 | @exit = ->
27 | document[polyfill.exit]()
28 | return
29 |
30 | @request = (elem) ->
31 | elem[polyfill.request]()
32 | return
33 |
34 | return
35 |
--------------------------------------------------------------------------------
/src/client/webchimera/services/wc-next-video.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | angular.module 'app.webchimera'
4 |
5 | .service 'wcNextVideoService', ($http, $q, $sce) ->
6 | deferred = $q.defer()
7 |
8 | @loadData = (url) ->
9 | $http.get(url).then @onLoadData.bind(this), @onLoadError.bind(this)
10 | deferred.promise
11 |
12 | @onLoadData = (response) ->
13 | result = []
14 | i = 0
15 | l = response.data.length
16 |
17 | while i < l
18 | mediaSources = []
19 | mi = 0
20 | ml = response.data[i].length
21 |
22 | while mi < ml
23 | mediaFile =
24 | src: $sce.trustAsResourceUrl response.data[i][mi].src
25 | type: response.data[i][mi].type
26 | mediaSources.push mediaFile
27 | mi++
28 |
29 | result.push mediaSources
30 | i++
31 |
32 | deferred.resolve result
33 |
34 | @onLoadError = (error) ->
35 | deferred.reject error
36 |
37 | @
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-bottom-controls.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-buffering.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-close-button.html:
--------------------------------------------------------------------------------
1 |
5 | close
6 |
7 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-fullscreen-button.html:
--------------------------------------------------------------------------------
1 |
5 | {{ fullscreenIcon }}
6 |
7 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-media.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-mute-button.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-next-video.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | cancel
6 |
7 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-overlay-play.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | play_circle_filled
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-play-pause-button.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-playback-button.html:
--------------------------------------------------------------------------------
1 | {{playback}}x
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-poster.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-scrub-bar-cue-points.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-scrub-bar.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-title.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-top-controls.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-torrent-info.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | close
4 |
5 |
6 | {{ player.detail.title }}
7 | {{ player.episode.title }}
8 |
9 |
10 |
15 |
--------------------------------------------------------------------------------
/src/client/webchimera/views/directives/wc-volume-bar.html:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/scripts/app-menu.coffee:
--------------------------------------------------------------------------------
1 | Menu = require 'menu'
2 |
3 | { EventEmitter } = require 'events'
4 |
5 | class AppMenu extends EventEmitter
6 | constructor: ->
7 | super()
8 |
9 | template = require './menus/' + process.platform
10 |
11 | @wireUpCommands template
12 | @menu = Menu.buildFromTemplate template
13 |
14 | makeDefault: ->
15 | Menu.setApplicationMenu @menu
16 |
17 | wireUpCommands: (submenu) ->
18 | submenu.forEach (item) =>
19 | if item.command
20 | existingOnClick = item.click
21 |
22 | item.click = =>
23 | @emit item.command, item
24 |
25 | if existingOnClick
26 | existingOnClick()
27 |
28 | if item.submenu
29 | @wireUpCommands item.submenu
30 |
31 | module.exports = AppMenu
32 |
--------------------------------------------------------------------------------
/src/scripts/application.coffee:
--------------------------------------------------------------------------------
1 | app = require 'app'
2 | path = require 'path'
3 | shell = require 'shell'
4 | window = require 'browser-window'
5 |
6 | { EventEmitter } = require 'events'
7 |
8 | AppMenu = require './app-menu'
9 | AppWindow = require './app-window'
10 |
11 | class Application extends EventEmitter
12 | constructor: (@port, @options) ->
13 | super()
14 |
15 | app.on 'window-all-closed', ->
16 | if process.platform isnt 'darwin'
17 | app.quit()
18 |
19 | @menu = @createMenu()
20 | @menu.makeDefault()
21 |
22 | @mainWindow = new AppWindow @options, @port
23 | @mainWindow.loadUrl 'file://' + path.resolve __dirname, '..', 'index.html'
24 |
25 | createMenu: ->
26 | menu = new AppMenu()
27 |
28 | menu.on 'application:quit', ->
29 | app.quit()
30 |
31 | menu.on 'application:open-url', (menuItem) ->
32 | shell.openExternal menuItem.url
33 |
34 | menu.on 'window:reload', ->
35 | window.getFocusedWindow().reload()
36 |
37 | menu.on 'window:toggle-full-screen', ->
38 | focusedWindow = window.getFocusedWindow()
39 | focusedWindow.setFullScreen not focusedWindow.isFullScreen()
40 |
41 | menu.on 'window:toggle-dev-tools', ->
42 | window.getFocusedWindow().toggleDevTools()
43 |
44 | menu
45 |
46 | module.exports = Application
47 |
--------------------------------------------------------------------------------
/src/scripts/main.coffee:
--------------------------------------------------------------------------------
1 | app = require 'app'
2 | main = require './application'
3 | manifest = require '../package.json'
4 | path = require 'path'
5 | getPort = require 'get-port'
6 |
7 | process.on 'uncaughtException', (error) ->
8 | console.error error.stack
9 |
10 | do ->
11 | app.on 'ready', ->
12 | getPort().then (port) ->
13 | global.application = new main manifest, port
14 | global.streamer = require(path.resolve(__dirname, '..', 'server/streamServer.js'))(port)
--------------------------------------------------------------------------------
/src/scripts/menus/linux.coffee:
--------------------------------------------------------------------------------
1 | { name, version } = require '../../package.json'
2 |
3 | module.exports = [
4 | {
5 | label: '&File'
6 | submenu: [
7 | { label: '&Settings', command: 'application:show-settings' }
8 | { label: '&Quit', accelerator: 'Ctrl+Q', command: 'application:quit' }
9 | ]
10 | }
11 |
12 | {
13 | label: '&View'
14 | submenu: [
15 | { label: '&Reload', accelerator: 'Ctrl+R', command: 'window:reload' }
16 | { label: 'Toggle &Full Screen', accelerator: 'F11', command: 'window:toggle-full-screen' }
17 | { label: 'Toggle &Developer Tools', accelerator: 'Alt+Ctrl+I', command: 'window:toggle-dev-tools' }
18 | ]
19 | }
20 |
21 | {
22 | label: '&Help'
23 | submenu: [
24 | { label: 'Version ' + version, enabled: false }
25 | { label: 'Check for Update', command: 'application:check-for-update' }
26 | { type: 'separator' }
27 | { label: '&Report Issue', command: 'application:open-url', url: 'https://github.com/butterproject/butter-desktop-angular/issues' }
28 | { label: '&Suggest Feature', command: 'application:open-url', url: 'https://github.com/butterproject/butter-desktop-angular/issues' }
29 | ]
30 | }
31 | ]
32 |
--------------------------------------------------------------------------------
/src/scripts/menus/win32.coffee:
--------------------------------------------------------------------------------
1 | { name, version } = require '../../package.json'
2 |
3 | module.exports = [
4 | {
5 | label: '&File'
6 | submenu: [
7 | { label: '&Settings', command: 'application:show-settings' }
8 | { label: 'E&xit', accelerator: 'Ctrl+Q', command: 'application:quit' }
9 | ]
10 | }
11 |
12 | {
13 | label: '&View'
14 | submenu: [
15 | { label: '&Reload', accelerator: 'Ctrl+R', command: 'window:reload' }
16 | { label: 'Toggle &Full Screen', accelerator: 'F11', command: 'window:toggle-full-screen' }
17 | { label: 'Toggle &Developer Tools', accelerator: 'Alt+Ctrl+I', command: 'window:toggle-dev-tools' }
18 | ]
19 | }
20 |
21 | {
22 | label: '&Help'
23 | submenu: [
24 | { label: 'Version ' + version, enabled: false }
25 | { label: 'Check for &Update', command: 'application:check-for-update' }
26 | { type: 'separator' }
27 | { label: '&Report Issue', command: 'application:open-url', url: 'https://github.com/butterproject/butter-desktop-angular/issues' }
28 | { label: '&Suggest Feature', command: 'application:open-url', url: 'https://github.com/butterproject/butter-desktop-angular/issues' }
29 | ]
30 | }
31 | ]
32 |
--------------------------------------------------------------------------------
/src/server/ffmpegService.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | ffmpeg = require 'fluent-ffmpeg'
4 | nodeFs = require 'fs'
5 | pump = require 'pump'
6 | $q = require 'Q'
7 |
8 | exports.ffmpegService =
9 | (req, res, torrent, file) ->
10 | param = req.query.ffmpeg
11 |
12 | probe = ->
13 | defer = $q.defer()
14 | filePath = path.join torrent.path, file.path
15 |
16 | nodeFs.exists filePath, (exists) ->
17 | if !exists
18 | return defer.reject 'File doesn`t exist.'
19 |
20 | ffmpeg.ffprobe filePath, (err, metadata) ->
21 | if err
22 | defer.reject err.toString()
23 |
24 | defer.resolve metadata
25 |
26 | defer.promise
27 |
28 | remux = ->
29 | res.type 'video/webm'
30 |
31 | command = ffmpeg(file.createReadStream())
32 | .videoCodec('libvpx')
33 | .audioCodec('libvorbis')
34 | .format('webm')
35 | .audioBitrate(128)
36 | .videoBitrate(1024)
37 | .outputOptions [
38 | #'-threads 2'
39 | '-deadline realtime'
40 | '-error-resilient 1'
41 | ]
42 |
43 | pump command, res
44 |
45 | switch param
46 | when 'probe'
47 | return probe()
48 | when 'remux'
49 | return remux()
50 | else res.send 501, 'Not supported.'
51 |
--------------------------------------------------------------------------------
/src/server/socketActions.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = (io, torrentStore) ->
4 | io.sockets.on 'connection', (socket) ->
5 | socket.on 'pause', (infoHash) ->
6 | torrent = torrentStore.get(infoHash)
7 |
8 | if torrent and torrent.swarm
9 | torrent.swarm.pause()
10 |
11 | socket.on 'resume', (infoHash) ->
12 | torrent = torrentStore.get(infoHash)
13 |
14 | if torrent and torrent.swarm
15 | torrent.swarm.resume()
16 |
17 | socket.on 'select', (infoHash, file) ->
18 | torrent = torrentStore.get(infoHash)
19 |
20 | if torrent and torrent.files
21 | file = torrent.files[file]
22 | file.select()
23 |
24 | socket.on 'deselect', (infoHash, file) ->
25 | torrent = torrentStore.get(infoHash)
26 |
27 | if torrent and torrent.files
28 | file = torrent.files[file]
29 | file.deselect()
--------------------------------------------------------------------------------
/src/server/streamerEngine.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | streamOptions = require './streamOptions'
4 |
5 | torrentStream = require 'torrent-stream'
6 |
7 | module.exports = (torrent) ->
8 | engine = torrentStream torrent, streamOptions
9 |
10 | engine.once 'verifying', ->
11 | console.log 'verifying ' + engine.infoHash
12 |
13 | engine.files.forEach (file, i) ->
14 | console.log i + ' ' + file.name
15 |
16 | engine.once 'verify', ->
17 | engine.verified = true
18 |
19 | engine.once 'ready', ->
20 | engine.ready = true
21 |
22 | # select the largest file
23 | file = engine.files.reduce (a, b) ->
24 | if a.length > b.length then a else b
25 |
26 | file.select()
27 |
28 | #engine.on 'uninterested', ->
29 | # console.log 'uninterested ' + engine.infoHash
30 |
31 | #engine.on 'interested', ->
32 | # console.log 'interested ' + engine.infoHash
33 |
34 | #engine.on 'idle', ->
35 | # console.log 'idle ' + engine.infoHash
36 |
37 | #engine.on 'error', (e) ->
38 | # console.log 'error ' + engine.infoHash + ': ' + e
39 |
40 | engine.once 'destroyed', ->
41 | console.log 'destroyed ' + engine.infoHash
42 | engine.removeAllListeners()
43 |
44 | engine.listen streamOptions.port, ->
45 | console.log 'listening ' + engine.infoHash + ' on port ' + engine.port
46 |
47 | engine
48 |
--------------------------------------------------------------------------------
/src/server/throttle.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = (func, wait) ->
4 | ctx = undefined
5 | args = undefined
6 | rtn = undefined
7 | timeoutID = undefined
8 |
9 | last = 0
10 |
11 | call = ->
12 | timeoutID = 0
13 | last = +new Date
14 | rtn = func.apply(ctx, args)
15 | ctx = null
16 | args = null
17 | return
18 |
19 | ->
20 | ctx = this
21 | args = arguments
22 | delta = new Date - last
23 |
24 | if !timeoutID
25 | if delta >= wait
26 | call()
27 | else timeoutID = setTimeout(call, wait - delta)
28 |
29 | rtn
--------------------------------------------------------------------------------
/src/server/torrentProgress.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | torrentUtils = require './torrentUtils'
4 |
5 | module.exports = (torrent) ->
6 | buffer = torrent.bitfield.buffer
7 |
8 | progress = []
9 | counter = 0
10 | downloaded = true
11 |
12 | i = 0
13 |
14 | while i < buffer.length
15 | p = buffer[i]
16 |
17 | if downloaded and p > 0 or !downloaded and p == 0
18 | counter++
19 | else
20 | progress.push counter
21 | counter = 1
22 | downloaded = !downloaded
23 |
24 | i++
25 |
26 | progress.push counter
27 |
28 | progress
29 | .map (p) -> p * 100 / buffer.length
30 | .filter (p, i) ->
31 | if torrent.files[i]?.name
32 | torrentUtils.isVideo torrent.files[i].name
33 |
--------------------------------------------------------------------------------
/src/server/torrentStats.coffee:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = (torrent) ->
4 | swarm = torrent.swarm
5 |
6 | notChoked = (prev, wire) ->
7 | prev + !wire.peerChoking
8 |
9 | peers:
10 | total: swarm.wires.length
11 | unchocked: swarm.wires.reduce notChoked, 0
12 |
13 | traffic:
14 | down: swarm.downloaded
15 | up: swarm.uploaded
16 |
17 | speed:
18 | down: swarm.downloadSpeed()
19 | up: swarm.uploadSpeed()
20 |
21 | queue: swarm.queued
22 | paused: swarm.paused
23 |
--------------------------------------------------------------------------------
/src/vendor/openssl/ia32/HashInfo.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/vendor/openssl/ia32/HashInfo.txt
--------------------------------------------------------------------------------
/src/vendor/openssl/ia32/libeay32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/vendor/openssl/ia32/libeay32.dll
--------------------------------------------------------------------------------
/src/vendor/openssl/ia32/openssl.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/vendor/openssl/ia32/openssl.exe
--------------------------------------------------------------------------------
/src/vendor/openssl/ia32/ssleay32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/vendor/openssl/ia32/ssleay32.dll
--------------------------------------------------------------------------------
/src/vendor/openssl/shared/cacert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIC2DCCAkGgAwIBAgIJAMEXhl9ZLpFbMA0GCSqGSIb3DQEBBAUAMFIxEzARBgNV
3 | BAoTCk15IENvbXBhbnkxEDAOBgNVBAcTB015IFRvd24xHDAaBgNVBAgTE1N0YXRl
4 | IG9yIFByb3ZpZGVuY2UxCzAJBgNVBAYTAkVFMB4XDTE1MDMyNDExNTcxOVoXDTE2
5 | MDMyMzExNTcxOVowUjETMBEGA1UEChMKTXkgQ29tcGFueTEQMA4GA1UEBxMHTXkg
6 | VG93bjEcMBoGA1UECBMTU3RhdGUgb3IgUHJvdmlkZW5jZTELMAkGA1UEBhMCRUUw
7 | gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKW/BmTIfxhXc8MxnSU7g2kXdspo
8 | mC84J35R8rVV6oGmJui9/Kk1WCp8h+L44jo1q4kZnFVYL0DFJ/XsUdNLKEduBatE
9 | xs+VRfjPxbnUlXAgx9YoEXITeyx0fsdDXqp8DC9xLAp6XP/8vG5WmjHsrdBX8Beq
10 | 4vT3Y28TY0QA6H5LAgMBAAGjgbUwgbIwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU
11 | K5VrBYO8sBM6QbHWrxDLol9sN/YwgYIGA1UdIwR7MHmAFCuVawWDvLATOkGx1q8Q
12 | y6JfbDf2oVakVDBSMRMwEQYDVQQKEwpNeSBDb21wYW55MRAwDgYDVQQHEwdNeSBU
13 | b3duMRwwGgYDVQQIExNTdGF0ZSBvciBQcm92aWRlbmNlMQswCQYDVQQGEwJFRYIJ
14 | AMEXhl9ZLpFbMA0GCSqGSIb3DQEBBAUAA4GBAAqmhakqo/JUT0/iFrtHMCSsN9+N
15 | z20Iy+WAgYXkVQaHUxvBYHD4Oyki7IZUlFmQsx2yO/gOWAWOUC1y040ftlUGH8Wr
16 | dGHenoqgMMsqy+M3BOajK711dc+hSlsXbV3LizJTEM/AOS6cbd0wcoLMwywmu1jb
17 | F5hOha4wzxjmOd3e
18 | -----END CERTIFICATE-----
19 |
--------------------------------------------------------------------------------
/src/vendor/openssl/shared/certindex.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/vendor/openssl/shared/certindex.txt
--------------------------------------------------------------------------------
/src/vendor/openssl/shared/private/cakey.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIICWwIBAAKBgQClvwZkyH8YV3PDMZ0lO4NpF3bKaJgvOCd+UfK1VeqBpibovfyp
3 | NVgqfIfi+OI6NauJGZxVWC9AxSf17FHTSyhHbgWrRMbPlUX4z8W51JVwIMfWKBFy
4 | E3ssdH7HQ16qfAwvcSwKelz//LxuVpox7K3QV/AXquL092NvE2NEAOh+SwIDAQAB
5 | AoGAbWYlmTYBNZbbcNX5jE640Q/Mt5LMCDa/UpBSa8BWtdZuTibAcwsjs39YzcZK
6 | w/MS0r5VwrsfDVhUpOyjoZw068g7nEFdUo7nDnU6vsvVJjE29VOQLIRcENNRp0Z/
7 | XagKpdw+48EEP7h31aiTiqfAzppjYhTTjOV53H4WfanwkgECQQDcI1UrYjwkjf1A
8 | 45tTDkTlOWFCUrQN8172JMyB3SdAihfTZGk7GzmicV1EEBNd7nt9s85YDZMh3dZc
9 | gmOGuD0BAkEAwL9T6N3nWhoXT/p42TkVyIHjpuRHyUrc3dZkf/oKQ4N6SKeznhO1
10 | sePRhvQhFTjXEtYhim41FMOo9z/4fAufSwJAOQuy624mdbaR1TnmK0y8T8ZhzMUP
11 | wbm6dwCsOk7r+A6RBAe2OUnh0pWb/KJJ0oKVX8qzgx/pa9JH1Ws4jVW7AQJAKypu
12 | C0eu6THQqLuqVtN++mGEbzrOjNj0L8Y0yahgphAK0byk8DDvzv/7S6Leydbp67EC
13 | 3/Kgdp7+9yhfaMBdkwJALPL4R8X54R9PyXeclNQAbLIPxuE/zCgQTvq96kOUURYD
14 | kxcXMe0Pvk2rEjHpIg8DLUl1Ah3dRIkCtIXcahYJPQ==
15 | -----END RSA PRIVATE KEY-----
16 |
--------------------------------------------------------------------------------
/src/vendor/openssl/shared/serial:
--------------------------------------------------------------------------------
1 | 100001
2 |
--------------------------------------------------------------------------------
/src/vendor/openssl/x64/HashInfo.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/vendor/openssl/x64/HashInfo.txt
--------------------------------------------------------------------------------
/src/vendor/openssl/x64/libeay32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/vendor/openssl/x64/libeay32.dll
--------------------------------------------------------------------------------
/src/vendor/openssl/x64/openssl.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/vendor/openssl/x64/openssl.exe
--------------------------------------------------------------------------------
/src/vendor/openssl/x64/ssleay32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/butterproject/butter-desktop-angular/ba9c5941eccefd5f00cd85359c4f32f73f4064d2/src/vendor/openssl/x64/ssleay32.dll
--------------------------------------------------------------------------------