Rework stats display
This commit is contained in:
		
							parent
							
								
									9951842594
								
							
						
					
					
						commit
						cd2827791f
					
				
					 3 changed files with 86 additions and 24 deletions
				
			
		| 
						 | 
					@ -53,9 +53,11 @@ html
 | 
				
			||||||
        outline: 1px solid black;
 | 
					        outline: 1px solid black;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
  body.themed.theme-system.overflow-y-scroll(hx-boost="true")
 | 
					  body.themed.theme-system.overflow-y-scroll(hx-boost="true")
 | 
				
			||||||
    header.s-topbar
 | 
					    header.s-topbar.ps-sticky.t0
 | 
				
			||||||
      .s-topbar--container.wmx9
 | 
					      .s-topbar--container.wmx9
 | 
				
			||||||
        .s-topbar--logo BC Explorer
 | 
					        .s-topbar--logo
 | 
				
			||||||
 | 
					          != icons.get("compass-solid", 24)
 | 
				
			||||||
 | 
					          .ml4 BC Explorer
 | 
				
			||||||
        .fl-grow1
 | 
					        .fl-grow1
 | 
				
			||||||
        nav
 | 
					        nav
 | 
				
			||||||
          ul.s-navigation
 | 
					          ul.s-navigation
 | 
				
			||||||
| 
						 | 
					@ -78,7 +80,7 @@ html
 | 
				
			||||||
        block view
 | 
					        block view
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      div
 | 
					      div
 | 
				
			||||||
        .ps-sticky.t24.d-flex.fd-column.g12
 | 
					        .ps-sticky.d-flex.fd-column.g12(style="top: 80px")
 | 
				
			||||||
          if filter
 | 
					          if filter
 | 
				
			||||||
            .s-sidebarwidget.s-sidebarwidget__blue.d-flex.ai-center.gx16.jc-space-between.p8.pl16
 | 
					            .s-sidebarwidget.s-sidebarwidget__blue.d-flex.ai-center.gx16.jc-space-between.p8.pl16
 | 
				
			||||||
              != icons.get("search")
 | 
					              != icons.get("search")
 | 
				
			||||||
| 
						 | 
					@ -87,8 +89,56 @@ html
 | 
				
			||||||
              a.s-btn.s-notice--btn(href=and({filter: null, filter_field: null})) Clear
 | 
					              a.s-btn.s-notice--btn(href=and({filter: null, filter_field: null})) Clear
 | 
				
			||||||
          .s-sidebarwidget.wmn3
 | 
					          .s-sidebarwidget.wmn3
 | 
				
			||||||
            .s-sidebarwidget--header Collection
 | 
					            .s-sidebarwidget--header Collection
 | 
				
			||||||
 | 
					              a.s-sidebarwidget--action Refresh
 | 
				
			||||||
            table.s-sidebarwidget--content.s-sidebarwidget__items
 | 
					            table.s-sidebarwidget--content.s-sidebarwidget__items
 | 
				
			||||||
              each stat in count
 | 
					 | 
				
			||||||
              tr.s-sidebarwidget--item
 | 
					              tr.s-sidebarwidget--item
 | 
				
			||||||
                  th= stat[0]
 | 
					                th items
 | 
				
			||||||
                  td= stat[1]
 | 
					                td= count.total
 | 
				
			||||||
 | 
					              tr.s-sidebarwidget--item
 | 
				
			||||||
 | 
					                th runtime
 | 
				
			||||||
 | 
					                td= count.runtime
 | 
				
			||||||
 | 
					              tr.s-sidebarwidget--item
 | 
				
			||||||
 | 
					                th format
 | 
				
			||||||
 | 
					                td
 | 
				
			||||||
 | 
					                  = count.albums
 | 
				
			||||||
 | 
					                  span.fc-black-400= ` albums`
 | 
				
			||||||
 | 
					                  span.fc-black-250= ` / `
 | 
				
			||||||
 | 
					                  = count.singles
 | 
				
			||||||
 | 
					                  span.fc-black-400= ` singles`
 | 
				
			||||||
 | 
					              tr.s-sidebarwidget--item
 | 
				
			||||||
 | 
					                th price
 | 
				
			||||||
 | 
					                td
 | 
				
			||||||
 | 
					                  = count.free
 | 
				
			||||||
 | 
					                  span.fc-black-400= ` free`
 | 
				
			||||||
 | 
					                  span.fc-black-250= ` / `
 | 
				
			||||||
 | 
					                  = count.paid
 | 
				
			||||||
 | 
					                  span.fc-black-400= ` paid`
 | 
				
			||||||
 | 
					              tr.s-sidebarwidget--item
 | 
				
			||||||
 | 
					                th tracks
 | 
				
			||||||
 | 
					                td
 | 
				
			||||||
 | 
					                  = count.tracks
 | 
				
			||||||
 | 
					                  span.pl8.fc-black-250= ` / `
 | 
				
			||||||
 | 
					                  span.fc-black-400 avg #{count.avgTracks}
 | 
				
			||||||
 | 
					              tr.s-sidebarwidget--item
 | 
				
			||||||
 | 
					                th tags
 | 
				
			||||||
 | 
					                td
 | 
				
			||||||
 | 
					                  = count.tags
 | 
				
			||||||
 | 
					                  span.pl8.fc-black-250= ` / `
 | 
				
			||||||
 | 
					                  span.fc-black-400 avg #{count.avgTags}
 | 
				
			||||||
 | 
					                  span.fc-black-250= ` / `
 | 
				
			||||||
 | 
					                  span.fc-black-400 lonely #{count.lonelyTags}
 | 
				
			||||||
 | 
					              tr.s-sidebarwidget--item
 | 
				
			||||||
 | 
					                th value
 | 
				
			||||||
 | 
					                td
 | 
				
			||||||
 | 
					                  = `${count.displayCurrencySymbol}${count.value} `
 | 
				
			||||||
 | 
					                  span.fc-black-400 #{count.displayCurrency}
 | 
				
			||||||
 | 
					              tr.s-sidebarwidget--item
 | 
				
			||||||
 | 
					                th diversity
 | 
				
			||||||
 | 
					                //- supernova red-500, warm yellow-500, hot orange-500
 | 
				
			||||||
 | 
					                //- 0-9 black, 10-99 yellow, 100-999 orange, 1000+ red
 | 
				
			||||||
 | 
					                td.w100
 | 
				
			||||||
 | 
					                  .s-progress.d-grid.g2.h4.mtn6(style=`grid-template-columns: ${count.taste.map(t => t + "fr").join(" ")}`).bg-white.fc-black-400.fs-fine.lh-xxl
 | 
				
			||||||
 | 
					                    .s-progress--bar.bg-black-400(title=`${count.taste[0]} labels with <20 fans`)= count.taste[0]
 | 
				
			||||||
 | 
					                    .s-progress--bar.bg-yellow-400(title=`${count.taste[1]} labels with 20-199 fans`)= count.taste[1]
 | 
				
			||||||
 | 
					                    .s-progress--bar.bg-orange-400(title=`${count.taste[2]} labels with 200-1999 fans`)= count.taste[2]
 | 
				
			||||||
 | 
					                    .s-progress--bar.bg-red-400(title=`${count.taste[3]} labels with >2000 fans`)= count.taste[3]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,19 +1,28 @@
 | 
				
			||||||
extends includes/layout.pug
 | 
					extends includes/layout.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
block view
 | 
					block view
 | 
				
			||||||
  .mx-auto.w100.wmx11.fs-body1#content(style="cursor: default")
 | 
					 | 
				
			||||||
  script
 | 
					  script
 | 
				
			||||||
    | var items =
 | 
					    | var items =
 | 
				
			||||||
    != JSON.stringify(items)
 | 
					    != JSON.stringify(items)
 | 
				
			||||||
 | 
					  .mx-auto.w100.wmx11.fs-body1
 | 
				
			||||||
 | 
					    if !items.length
 | 
				
			||||||
 | 
					      .d-flex.jc-center
 | 
				
			||||||
 | 
					        .s-notice.d-flex.ai-center.p8.gx16.pl16(role="status")
 | 
				
			||||||
 | 
					          != icons.get("info-circle")
 | 
				
			||||||
 | 
					          div Tag data needs to be downloaded. This will take a while.
 | 
				
			||||||
 | 
					          button.s-btn.s-btn__outlined Download now
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #content(style="cursor: default")
 | 
				
			||||||
  script.
 | 
					  script.
 | 
				
			||||||
    setTimeout(() => {
 | 
					    setTimeout(() => {
 | 
				
			||||||
      const content = document.getElementById("content")
 | 
					      const content = document.getElementById("content")
 | 
				
			||||||
      content.style.height = `${Math.round(Math.min(content.clientWidth, window.innerHeight)*0.8)}px`
 | 
					      content.style.height = `${Math.round(Math.min(content.clientWidth, window.innerHeight)*0.8)}px`
 | 
				
			||||||
 | 
					      const dark = window.matchMedia?.("(prefers-color-scheme: dark)").matches
 | 
				
			||||||
      WordCloud(content, {
 | 
					      WordCloud(content, {
 | 
				
			||||||
        list: items,
 | 
					        list: items,
 | 
				
			||||||
        fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI Adjusted", "Segoe UI", "Liberation Sans", sans-serif',
 | 
					        fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI Adjusted", "Segoe UI", "Liberation Sans", sans-serif',
 | 
				
			||||||
        fontWeight: "bold",
 | 
					        fontWeight: "bold",
 | 
				
			||||||
        color: "random-dark",
 | 
					        color: dark ? "random-light": "random-dark",
 | 
				
			||||||
        minSize: 4,
 | 
					        minSize: 4,
 | 
				
			||||||
        gridSize: Math.round(content.clientWidth / 200),
 | 
					        gridSize: Math.round(content.clientWidth / 200),
 | 
				
			||||||
        weightFactor: size => size * content.clientWidth / 180,
 | 
					        weightFactor: size => size * content.clientWidth / 180,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -102,22 +102,25 @@ router.get("/", defineEventHandler({
 | 
				
			||||||
		const locals = {
 | 
							const locals = {
 | 
				
			||||||
			items: prepared.all(params),
 | 
								items: prepared.all(params),
 | 
				
			||||||
			query,
 | 
								query,
 | 
				
			||||||
			count: [
 | 
								count: {
 | 
				
			||||||
				["total", db.prepare("SELECT count(*) FROM item").pluck().get()],
 | 
									total: db.prepare("SELECT count(*) FROM item").pluck().get(),
 | 
				
			||||||
				["runtime", db.prepare("SELECT iif(sum(duration) > 86400, cast(total(duration)/86400 AS INTEGER) || 'd ' || cast(total(duration)/3600%24 AS INTEGER) || 'h', cast(total(duration)/3600 AS INTEGER) || 'h') FROM track").pluck().get()],
 | 
									runtime: db.prepare("SELECT iif(sum(duration) > 86400, cast(total(duration)/86400 AS INTEGER) || 'd ' || cast(total(duration)/3600%24 AS INTEGER) || 'h', cast(total(duration)/3600 AS INTEGER) || 'h') FROM track").pluck().get(),
 | 
				
			||||||
				["albums", db.prepare("SELECT count(*) FROM item WHERE item_type = 'album'").pluck().get()],
 | 
									albums: db.prepare("SELECT count(*) FROM item WHERE item_type = 'album'").pluck().get(),
 | 
				
			||||||
				["singles", db.prepare("SELECT count(*) FROM item WHERE item_type = 'track'").pluck().get()],
 | 
									singles: db.prepare("SELECT count(*) FROM item WHERE item_type = 'track'").pluck().get(),
 | 
				
			||||||
				["free", db.prepare("SELECT count(*) FROM item WHERE price = 0").pluck().get()],
 | 
									free: db.prepare("SELECT count(*) FROM item WHERE price = 0").pluck().get(),
 | 
				
			||||||
				["paid", db.prepare("SELECT count(*) FROM item WHERE price > 0").pluck().get()],
 | 
									paid: db.prepare("SELECT count(*) FROM item WHERE price > 0").pluck().get(),
 | 
				
			||||||
				["tracks", db.prepare("SELECT count(*) FROM track").pluck().get()],
 | 
									tracks: db.prepare("SELECT count(*) FROM track").pluck().get(),
 | 
				
			||||||
				["avg tracks", Math.round(db.prepare("SELECT avg(count) FROM (SELECT count(*) AS count FROM track INNER JOIN item USING (item_id) WHERE item_type = 'album' GROUP BY item_id)").pluck().get()*10)/10],
 | 
									avgTracks: Math.round(db.prepare("SELECT avg(count) FROM (SELECT count(*) AS count FROM track INNER JOIN item USING (item_id) WHERE item_type = 'album' GROUP BY item_id)").pluck().get()*10)/10,
 | 
				
			||||||
				["tags", db.prepare("SELECT count(*) FROM item_tag").pluck().get()],
 | 
									tags: db.prepare("SELECT count(*) FROM item_tag").pluck().get(),
 | 
				
			||||||
				["avg tags", Math.round(db.prepare("SELECT avg(count) FROM (SELECT count(*) AS count FROM item_tag GROUP BY item_id)").pluck().get()*10)/10],
 | 
									avgTags: Math.round(db.prepare("SELECT avg(count) FROM (SELECT count(*) AS count FROM item_tag GROUP BY item_id)").pluck().get()*10)/10,
 | 
				
			||||||
				["lonely tags", db.prepare("SELECT count(*) FROM (SELECT tag FROM item_tag GROUP BY tag HAVING count(*) = 1)").pluck().get()],
 | 
									lonelyTags: db.prepare("SELECT count(*) FROM (SELECT tag FROM item_tag GROUP BY tag HAVING count(*) = 1)").pluck().get(),
 | 
				
			||||||
				["value", displayCurrencySymbol + Math.round(select("item", ["currency", "price"]).all().map(c => {
 | 
									value: Math.round(select("item", ["currency", "price"]).all().map(c => {
 | 
				
			||||||
					return (currencyExchange.get(c.currency) || 0.6) * c.price / (currencyExchange.get(displayCurrency) || 1) / 10
 | 
										return (currencyExchange.get(c.currency) || 0.6) * c.price / (currencyExchange.get(displayCurrency) || 1) / 10
 | 
				
			||||||
				}).reduce((a, c) => a + c, 0)) * 10 + " " + displayCurrency]
 | 
									}).reduce((a, c) => a + c, 0)) * 10,
 | 
				
			||||||
			]
 | 
									displayCurrency,
 | 
				
			||||||
 | 
									displayCurrencySymbol,
 | 
				
			||||||
 | 
									taste: db.prepare("with popularity (a) as (select avg(also_collected_count) from item group by band_url) select sum(iif(a >= 0 and a < 20, 1, 0)) as cold, sum(iif(a >= 20 and a < 200, 1, 0)) as warm, sum(iif(a >= 200 and a < 2000, 1, 0)) as hot, sum(iif(a >= 2000, 1, 0)) as supernova from popularity").raw().get()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (mode === "artist_grid") {
 | 
							if (mode === "artist_grid") {
 | 
				
			||||||
			loadPreviews(locals, "band_name", 4, whereClause, filter_field, filter)
 | 
								loadPreviews(locals, "band_name", 4, whereClause, filter_field, filter)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue