summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--animism-align/cli/app/controllers/annotation_controller.py17
-rw-r--r--animism-align/cli/app/controllers/crud_controller.py6
-rw-r--r--animism-align/cli/app/controllers/media_controller.py8
-rw-r--r--animism-align/cli/app/controllers/paragraph_controller.py8
-rw-r--r--animism-align/cli/app/settings/app_cfg.py9
-rw-r--r--animism-align/frontend/app/api/crud.fetch.js2
-rw-r--r--animism-align/frontend/app/common/table.component.js4
-rw-r--r--animism-align/frontend/app/views/editor/editor.gate.js13
-rw-r--r--animism-align/frontend/app/views/editor/overview/overview.container.js42
-rw-r--r--animism-align/frontend/app/views/editor/overview/overview.css8
-rw-r--r--animism-align/frontend/app/views/nav/header.component.js2
-rw-r--r--animism-align/frontend/app/views/site/site.actions.js5
-rw-r--r--animism-align/frontend/app/views/viewer/viewer.actions.js5
13 files changed, 105 insertions, 24 deletions
diff --git a/animism-align/cli/app/controllers/annotation_controller.py b/animism-align/cli/app/controllers/annotation_controller.py
index aed7310..78947a8 100644
--- a/animism-align/cli/app/controllers/annotation_controller.py
+++ b/animism-align/cli/app/controllers/annotation_controller.py
@@ -9,8 +9,16 @@ from app.controllers.crud_controller import CrudView
class AnnotationView(CrudView):
model = Annotation
form = AnnotationForm
+ index_all = False
+ use_limit = False
default_sort = "start_ts"
+ def where(self, query, args):
+ episode_id = args.get('episode_id', default=None)
+ if episode_id is not None:
+ query = query.filter(Annotation.episode_id == int(episode_id))
+ return query
+
def on_create(self, session, form, item):
if 'paragraph_id' in form:
item.paragraph_id = form['paragraph_id']
@@ -46,8 +54,15 @@ class AnnotationView(CrudView):
session.close()
return { 'status': 'error', 'error': 'duration is invalid '}
+ try:
+ episode_id = float(request.json['episode_id'])
+ except:
+ print("Annotation splice: episode_id is undefined")
+ session.close()
+ return { 'status': 'error', 'error': 'episode_id is invalid '}
+
query = session.query(self.model)
- query = query.filter(Annotation.start_ts > start_ts)
+ query = query.filter(Annotation.start_ts > start_ts, Annotation.episode_id == episode_id)
items = query.all()
print(f"{len(items)} annotations would be updated")
diff --git a/animism-align/cli/app/controllers/crud_controller.py b/animism-align/cli/app/controllers/crud_controller.py
index 29a570a..ace84f3 100644
--- a/animism-align/cli/app/controllers/crud_controller.py
+++ b/animism-align/cli/app/controllers/crud_controller.py
@@ -11,6 +11,7 @@ class CrudView(FlaskView):
# model = Collection
# form = CollectionForm
index_all = True
+ use_limit = True
excluded_methods = ['on_index', 'on_show', 'on_create', 'on_update', 'on_destroy']
default_sort = "id"
default_order = "asc"
@@ -46,7 +47,10 @@ class CrudView(FlaskView):
query = query.order_by(order_by, order_by_id)
else:
query = query.order_by(order_by)
- items = query.offset(offset).limit(limit).all()
+ if self.use_limit:
+ items = query.offset(offset).limit(limit).all()
+ else:
+ items = query.all()
res = self.on_index(session, {
'status': 'ok',
diff --git a/animism-align/cli/app/controllers/media_controller.py b/animism-align/cli/app/controllers/media_controller.py
index e7e620c..77f7ac2 100644
--- a/animism-align/cli/app/controllers/media_controller.py
+++ b/animism-align/cli/app/controllers/media_controller.py
@@ -9,6 +9,14 @@ from app.controllers.crud_controller import CrudView
class MediaView(CrudView):
model = Media
form = MediaForm
+ index_all = False
+ use_limit = False
+
+ def where(self, query, args):
+ episode_id = args.get('episode_id', default=None)
+ if episode_id is not None:
+ query = query.filter(Media.episode_id == int(episode_id))
+ return query
def on_create(self, session, form, item):
if 'settings' in form:
diff --git a/animism-align/cli/app/controllers/paragraph_controller.py b/animism-align/cli/app/controllers/paragraph_controller.py
index 807135d..9e6d4bc 100644
--- a/animism-align/cli/app/controllers/paragraph_controller.py
+++ b/animism-align/cli/app/controllers/paragraph_controller.py
@@ -9,8 +9,16 @@ from app.controllers.crud_controller import CrudView
class ParagraphView(CrudView):
model = Paragraph
form = ParagraphForm
+ index_all = False
+ use_limit = False
default_sort = "start_ts"
+ def where(self, query, args):
+ episode_id = args.get('episode_id', default=None)
+ if episode_id is not None:
+ query = query.filter(Paragraph.episode_id == int(episode_id))
+ return query
+
def on_create(self, session, form, item):
if 'settings' in form:
item.settings = form['settings']
diff --git a/animism-align/cli/app/settings/app_cfg.py b/animism-align/cli/app/settings/app_cfg.py
index ceb9e43..6d5f4c0 100644
--- a/animism-align/cli/app/settings/app_cfg.py
+++ b/animism-align/cli/app/settings/app_cfg.py
@@ -76,6 +76,13 @@ HASH_BRANCH_SIZE = 3 # for sha256 subdirs
USE_SQLITE = os.getenv("USE_SQLITE") == "True"
# -----------------------------------------------------------------------------
+# APIs
+# -----------------------------------------------------------------------------
+
+DEFAULT_LIMIT = 50
+MAX_LIMIT = 1000
+
+# -----------------------------------------------------------------------------
# S3 storage
# -----------------------------------------------------------------------------
@@ -85,7 +92,7 @@ except Exception as e:
pass
# -----------------------------------------------------------------------------
-# Le crypto
+# Le crypto~
# -----------------------------------------------------------------------------
TOKEN_SECRET = os.getenv("TOKEN_SECRET") or None
diff --git a/animism-align/frontend/app/api/crud.fetch.js b/animism-align/frontend/app/api/crud.fetch.js
index ddcd80b..348f97f 100644
--- a/animism-align/frontend/app/api/crud.fetch.js
+++ b/animism-align/frontend/app/api/crud.fetch.js
@@ -45,7 +45,7 @@ export function crud_fetch(type, tag) {
function _get_url(_url, data) {
const url = new URL(window.location.origin + _url)
if (data) {
- Object.keys(data).forEach(key => url.searchParams.append(key, data[key]))
+ Object.keys(data).forEach(key => url.searchParams.set(key, data[key]))
}
return url
}
diff --git a/animism-align/frontend/app/common/table.component.js b/animism-align/frontend/app/common/table.component.js
index b26dcba..eada263 100644
--- a/animism-align/frontend/app/common/table.component.js
+++ b/animism-align/frontend/app/common/table.component.js
@@ -4,7 +4,7 @@ import { formatName } from 'app/utils'
const __HR__ = '__HR__'
-export function TableObject({ tag, object, order, summary }) {
+export function TableObject({ tag, object, order, summary, className }) {
if (!object) return null
if (object === 'loading') {
return <div className='tableObject loading'>{tag}{': Loading'}</div>
@@ -37,7 +37,7 @@ export function TableObject({ tag, object, order, summary }) {
return (
<div>
{tag && <h3 className='tt'>{tag}</h3>}
- <table className={'tableObject ' + tag}>
+ <table className={'tableObject ' + (className || "")}>
<tbody>
{objects.map((key, i) => (
<TableRow key={key + '_' + i} name={key} value={object[key]} />
diff --git a/animism-align/frontend/app/views/editor/editor.gate.js b/animism-align/frontend/app/views/editor/editor.gate.js
index 5076350..87ca367 100644
--- a/animism-align/frontend/app/views/editor/editor.gate.js
+++ b/animism-align/frontend/app/views/editor/editor.gate.js
@@ -6,9 +6,12 @@ import { Loader } from 'app/common'
import actions from 'app/actions'
class EditorGate extends Component {
+ state = {
+ ready: false,
+ }
+
constructor(props) {
super(props)
- this.load()
}
componentDidMount() {
@@ -30,13 +33,17 @@ class EditorGate extends Component {
if (!this.props.episode.lookup) return
if (!this.props.episode_id) return
if (parseInt(this.props.episode_id) === parseInt(this.props.current_episode_id)) return
+ this.setState({ ready: false })
const episode = this.props.episode.lookup[this.props.episode_id]
const project = this.props.project.lookup[episode.project_id]
actions.site.loadEpisode(project, episode)
+ .then(() => {
+ this.setState({ ready: true })
+ })
}
render() {
- if (parseInt(this.props.episode_id) === parseInt(this.props.current_episode_id)) {
+ if (this.state.ready && parseInt(this.props.episode_id) === parseInt(this.props.current_episode_id)) {
return this.props.children
}
return (
@@ -48,7 +55,7 @@ class EditorGate extends Component {
const mapStateToProps = state => ({
episode: state.episode.index,
project: state.project.index,
- current_episode_id: state.site.episode.id,
+ current_episode_id: state.site.episode ? state.site.episode.id : 0,
})
export default connect(mapStateToProps)(EditorGate) \ No newline at end of file
diff --git a/animism-align/frontend/app/views/editor/overview/overview.container.js b/animism-align/frontend/app/views/editor/overview/overview.container.js
index b06a299..d64bd9f 100644
--- a/animism-align/frontend/app/views/editor/overview/overview.container.js
+++ b/animism-align/frontend/app/views/editor/overview/overview.container.js
@@ -7,11 +7,11 @@ import './overview.css'
// import actions from 'app/actions'
import { Loader, TableObject } from 'app/common'
import { groupResponseBy } from 'app/utils/api.utils'
-import { courtesyS, formatDateTime } from 'app/utils'
+import { courtesyS, formatDateTime, timestampHMS } from 'app/utils'
class OverviewContainer extends Component {
state = {
- ready: true,
+ ready: false,
}
constructor(props) {
@@ -29,14 +29,26 @@ class OverviewContainer extends Component {
}
build() {
- // const episodes = groupResponseBy(this.props.episodes, 'project_id')
- // const venues = groupResponseBy(this.props.venues, 'project_id')
- // this.setState({ ready: true, episodes, venues })
+ const { annotation } = this.props
+ const stats = annotation.order.reduce((stats, annotation_id) => {
+ const { paragraph_id, type } = annotation.lookup[annotation_id]
+ if (paragraph_id) {
+ stats.paragraphs[paragraph_id] = true
+ }
+ if (!stats.types[type]) {
+ stats.types[type] = 0
+ }
+ stats.types[type] += 1
+ return stats
+ }, { types: {}, paragraphs: {} })
+ setTimeout(() => {
+ this.setState({ ready: true, stats })
+ }, 20)
}
render() {
- const { project, episode, media, annotation, align } = this.props
- const { ready } = this.state
+ const { project, episode, media, annotation, align, viewer } = this.props
+ const { ready, stats } = this.state
if (!ready) {
return (
<div className='overview'>
@@ -44,8 +56,7 @@ class OverviewContainer extends Component {
</div>
)
}
- // console.log(this.props)
- console.log(annotation.order.length)
+
return (
<div className='overview'>
<div className='project-top'>
@@ -53,15 +64,21 @@ class OverviewContainer extends Component {
<h1>{`${project.title}: Episode ${episode.episode_number}`}</h1>
<h2>{episode.title}</h2>
</div>
- <h3>Statistics</h3>
-
<TableObject
- className="overview"
+ tag="Overview"
order={"annotations".split(" ")}
object={{
annotations: courtesyS(annotation.order.length, 'annotation'),
+ media: media.order.length + ' media',
+ sections: courtesyS(viewer.sections.length, 'section'),
+ paragraphs: courtesyS(Object.keys(stats.paragraphs).length, 'paragraph'),
+ duration: timestampHMS(align.duration),
}}
/>
+ <TableObject
+ tag="Annotations"
+ object={stats.types}
+ />
</div>
</div>
)
@@ -73,6 +90,7 @@ const mapStateToProps = state => ({
episode: state.site.episode,
media: state.media.index,
annotation: state.annotation.index,
+ viewer: state.viewer,
align: state.align,
})
diff --git a/animism-align/frontend/app/views/editor/overview/overview.css b/animism-align/frontend/app/views/editor/overview/overview.css
index 2c8b903..6a6e292 100644
--- a/animism-align/frontend/app/views/editor/overview/overview.css
+++ b/animism-align/frontend/app/views/editor/overview/overview.css
@@ -5,3 +5,11 @@
.overview h2 {
margin: 0.5rem 0 1rem 0;
}
+
+.overview .tableObject th, .overview .tableTuples th {
+ color: #ddd;
+}
+
+.overview .tableObject td {
+ color: #eee;
+} \ No newline at end of file
diff --git a/animism-align/frontend/app/views/nav/header.component.js b/animism-align/frontend/app/views/nav/header.component.js
index 8443278..4e43657 100644
--- a/animism-align/frontend/app/views/nav/header.component.js
+++ b/animism-align/frontend/app/views/nav/header.component.js
@@ -14,7 +14,7 @@ function Header(props) {
return null
}
if (props.router.location.pathname.match("/editor")) {
- const episode_id = props.router.location.pathname.split('/')[1]
+ const episode_id = props.router.location.pathname.split('/')[2]
return (
<header>
<div>
diff --git a/animism-align/frontend/app/views/site/site.actions.js b/animism-align/frontend/app/views/site/site.actions.js
index a9d3deb..ac14096 100644
--- a/animism-align/frontend/app/views/site/site.actions.js
+++ b/animism-align/frontend/app/views/site/site.actions.js
@@ -20,17 +20,18 @@ export const loadSite = () => dispatch => {
export const loadEpisode = (project, episode) => dispatch => {
const { id: episode_id } = episode
dispatch({ type: types.editor.loading })
- Promise.all([
+ return Promise.all([
// actions.site.loadText(episode),
actions.site.loadPeaks(episode),
actions.audio.load(episode),
actions.annotation.index({ episode_id }),
actions.paragraph.index({ episode_id }),
actions.media.index({ episode_id }),
- ]).then(() => {
+ ]).then((results) => {
actions.viewer.loadSections()
dispatch({ type: types.editor.loaded, project, episode })
console.log('Episode loaded')
+ return results
}).catch(err => {
console.error(err)
})
diff --git a/animism-align/frontend/app/views/viewer/viewer.actions.js b/animism-align/frontend/app/views/viewer/viewer.actions.js
index ef98533..a2764ed 100644
--- a/animism-align/frontend/app/views/viewer/viewer.actions.js
+++ b/animism-align/frontend/app/views/viewer/viewer.actions.js
@@ -48,6 +48,11 @@ export const loadSections = () => dispatch => {
const { order: annotationOrder, lookup: annotationLookup } = state.annotation.index
const { lookup: mediaLookup } = state.media.index
+ if (annotationOrder.length === 0) {
+ dispatch({ type: types.viewer.load_sections, sections: [], footnoteList: [] })
+ return
+ }
+
// console.log(state)
// loop over the annotations in time order.