├── .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 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/images/flags/am.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/at.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/ax.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/images/flags/az.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/bd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/images/flags/be.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/bf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/images/flags/bg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/bh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/images/flags/bj.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/bq.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/bs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/assets/images/flags/bv.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/images/flags/cd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/cf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/images/flags/cg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/images/flags/ch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/assets/images/flags/cl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/images/flags/cm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/images/flags/cn.svg: -------------------------------------------------------------------------------- 1 | 2 | Flag of the People's Republic of China 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/images/flags/co.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/cr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/cu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/assets/images/flags/cw.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/assets/images/flags/cz.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/images/flags/de.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/dj.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/dk.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/images/flags/dz.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/images/flags/england.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/europeanunion.svg: -------------------------------------------------------------------------------- 1 | 2 | European flag 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/assets/images/flags/fo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/images/flags/fr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/ga.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/gb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/images/flags/gf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/images/flags/gg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/images/flags/gh.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/gl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/assets/images/flags/gm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/gn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/assets/images/flags/gr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/assets/images/flags/gw.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/gy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/images/flags/ht.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/hu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/images/flags/id.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/ie.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/is.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/images/flags/it.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/jm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/images/flags/jo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/images/flags/jp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/images/flags/kn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/kw.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/images/flags/la.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/images/flags/lc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/lt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/lv.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/ly.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/images/flags/ma.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/images/flags/mc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/images/flags/mg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/mm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/assets/images/flags/mr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/images/flags/mv.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/images/flags/ne.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/assets/images/flags/ng.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/images/flags/nl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/images/flags/northerncyprus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/images/flags/pa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/images/flags/pk.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/pl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/images/flags/pr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/images/flags/ps.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/pw.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/images/flags/qa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/images/flags/re.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/ro.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/assets/images/flags/ru.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/sc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/scotland.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/images/flags/sd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/images/flags/se.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/images/flags/sj.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/images/flags/sn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/so.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/images/flags/southossetia.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/assets/images/flags/sr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/images/flags/ss.svg: -------------------------------------------------------------------------------- 1 | 2 | Flag of South Sudan 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/images/flags/tf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/tg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/images/flags/th.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/images/flags/tl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/images/flags/to.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/images/flags/tr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/images/flags/tt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/assets/images/flags/tz.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/images/flags/ua.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/images/flags/vc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/assets/images/flags/ve.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/assets/images/flags/vn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/images/flags/wf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/ye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/flags/za.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/images/flags/zz.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 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 |
4 | 5 |
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 |
3 |

4 | 5 |

{{ show.genres.join(', ') }}

6 | 7 |

{{ show.year }}{{ show.type === "show" ? " - "(show.status ? show.status : "N/A") : "" }}

8 | 9 |

{{ show.runtime }} min

10 |
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 | -------------------------------------------------------------------------------- /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 |
8 |
9 | 12 |
13 |
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 |
2 | delete_forever Flush bookmarks database 3 | delete_forever Flush subtitles cache 4 | delete_forever Flush all databases 5 | restore Reset to Default Settings 6 |
7 | -------------------------------------------------------------------------------- /src/client/settings/templates/settings-cache.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Cache 4 |
5 | 6 |
7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | delete_forever Clear Tmp Folder after closing app? 18 | 19 | 20 | 21 |
22 |
23 | -------------------------------------------------------------------------------- /src/client/settings/templates/settings-database.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Database 4 |
5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | file_download 20 | Import Database 21 | 22 | 23 | file_upload 24 | Export Database 25 | 26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /src/client/settings/templates/settings-features.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Features 4 |
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 |
3 | Playback 4 |
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 |
3 | Quality 4 |
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 |
3 | settings 4 | Settings 5 |
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 |
3 | TV Show Time 4 |
5 | 6 |
7 | 8 |
9 |
You are currently connected to TVShow Time.
10 | Disconnect account 11 |
12 | 13 |
14 |
You are currently connected to TVShow Time.
15 | Disconnect account 16 |
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 |
2 |
3 |
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 |
2 |
3 |
-------------------------------------------------------------------------------- /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 |
11 |
{{ state }}
12 | 13 |
Download: {{ torrent.stats.speed.down | fileSize }} • Upload: {{ torrent.stats.speed.up | fileSize }} • Active Peers: {{ torrent.stats.peers.total }}
14 |
15 | -------------------------------------------------------------------------------- /src/client/webchimera/views/directives/wc-volume-bar.html: -------------------------------------------------------------------------------- 1 |
2 |
8 |
9 |
10 |
11 |
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 --------------------------------------------------------------------------------