UNPKG

ferment

Version:

Peer-to-peer audio publishing and streaming application. Like SoundCloud but decentralized. A mashup of ssb, webtorrent and electron.

153 lines (143 loc) 4.83 kB
var h = require('../lib/h') var send = require('@mmckegg/mutant/send') var computed = require('@mmckegg/mutant/computed') var when = require('@mmckegg/mutant/when') var AudioOverview = require('./audio-overview') var contextMenu = require('../lib/context-menu') var magnet = require('magnet-uri') var colorHash = require('../lib/color-hash') var humanTime = require('human-time') var TorrentStatusWidget = require('./torrent-status') module.exports = function (context, post) { var player = context.player || {} var infoHash = computed(post.audioSrc, (src) => magnet.decode(src).infoHash) var likesCount = computed(post.likes, x => x.length) var repostsCount = computed(post.reposters, (list) => list.length) var reposted = computed([context.profile && context.profile.posts, post.id], (posts, id) => posts && posts.includes(id)) var liked = computed([context.profile && context.profile.likes, post.id], (likes, id) => likes && likes.includes(id)) var isOwner = context.profile && context.profile.id === post.author.id var color = colorHash.hex(post.id) var url = computed(post.artworkSrc, context.api.getBlobUrl) return h('AudioPost', { 'ev-contextmenu': contextMenu.bind(null, context, post), 'data-info-hash': infoHash, 'data-duration': post.duration, classList: [ computed(post.state, (s) => `-${s}`) ] }, [ h('div.artwork', { style: { 'background-image': computed(url, (src) => src ? `url("${src}")` : ''), 'background-color': color, 'cursor': 'pointer' }, 'ev-click': send(context.actions.viewPost, post.id) }), h('div.main', [ h('div.title', [ h('a.play', { 'ev-click': send(player.togglePlay, post), href: '#' }), h('header', [ h('a.feedTitle', { href: '#', 'ev-click': send(context.actions.viewProfile, post.author.id) }, [post.author.displayName]), h('a.title', { href: '#', 'ev-click': send(context.actions.viewPost, post.id) }, [post.title]) ]), h('div.timestamp', [ humanTime(Date.now() / 1000 - post.timestamp() / 1000) ]) ]), h('div.display', { hooks: [ SetPositionHook(context, post) ] }, [ AudioOverview(post.overview, 600, 100), h('div.progress', { style: { width: computed([post.position, post.duration], (pos, dur) => Math.round(pos / dur * 1000) / 10 + '%') } }), when(post.position, h('span.position', computed(post.position, formatTime))), h('span.duration', computed(post.duration, formatTime)) ]), h('div.options', [ h('a.like', { href: '#', 'ev-click': send(toggleLike, { liked, context, post }), classList: [ when(liked, '-active') ] }, [ '💚 ', when(likesCount, likesCount, 'Like') ]), when(isOwner, h('a.repost -disabled', [ '📡 ', when(repostsCount, repostsCount, 'Repost') ]), h('a.repost', { href: '#', 'ev-click': send(toggleRepost, { reposted, context, post }), classList: [ when(reposted, '-active') ] }, [ '📡 ', when(repostsCount, repostsCount, 'Repost') ]) ), when(isOwner, h('a.edit', { href: '#', 'ev-click': edit }, '✨ Edit') ), h('a.save', { href: '#', 'ev-click': send(context.actions.saveFile, post) }, '💾 Save'), TorrentStatusWidget(context, infoHash) ]) ]) ]) function edit () { context.actions.editPost({ id: post.id, item: post() }) } } function toggleRepost (opts) { if (opts.reposted()) { opts.context.api.unrepost(opts.post.id) } else { opts.context.api.repost(opts.post.id) } } function toggleLike (opts) { if (opts.liked()) { opts.context.api.unlike(opts.post.id) } else { opts.context.api.like(opts.post.id) } } function SetPositionHook (context, item) { return function (element) { element.onmousemove = element.onmousedown = function (ev) { if (ev.buttons && ev.button === 0) { var box = ev.currentTarget.getBoundingClientRect() var x = ev.clientX - box.left if (x < 5) { x = 0 } setPosition(x / box.width * item.duration()) } } } function setPosition (position) { if (context.player.currentItem.get() === item) { context.player.audioElement.currentTime = position } item.position.set(position) } } function formatTime (value) { var minutes = Math.floor(value / 60) var seconds = Math.floor(value % 60) return minutes + ':' + ('0' + seconds).slice(-2) }