コミットを比較

...

3 コミット
master ... v2

作成者 SHA1 メッセージ 日付
  choj a014d9b1b9 v2 initial python script 3年前
  choj 8e6f937efb UI stuff + audio player implementation 4年前
  choj c4d7522dc7 début refonte v2 4年前
42個のファイルの変更595行の追加252行の削除
  1. +20
    -2
      README.md
  2. +102
    -0
      assets/css/labelize.css
  3. +108
    -0
      assets/css/player.css
  4. バイナリ
      assets/fonts/noto-sans/NotoSans-Bold.ttf
  5. バイナリ
      assets/fonts/noto-sans/NotoSans-BoldItalic.ttf
  6. バイナリ
      assets/fonts/noto-sans/NotoSans-Italic.ttf
  7. バイナリ
      assets/fonts/noto-sans/NotoSans-Regular.ttf
  8. +2
    -1
      assets/fonts/work-sans/SIL Open Font License.txt
  9. バイナリ
      assets/fonts/work-sans/WorkSans-Black.otf
  10. バイナリ
      assets/fonts/work-sans/WorkSans-BlackItalic.otf
  11. バイナリ
      assets/fonts/work-sans/WorkSans-Bold.otf
  12. バイナリ
      assets/fonts/work-sans/WorkSans-BoldItalic.otf
  13. バイナリ
      assets/fonts/work-sans/WorkSans-ExtraBold.otf
  14. バイナリ
      assets/fonts/work-sans/WorkSans-ExtraBoldItalic.otf
  15. バイナリ
      assets/fonts/work-sans/WorkSans-ExtraLight.otf
  16. バイナリ
      assets/fonts/work-sans/WorkSans-ExtraLightItalic.otf
  17. バイナリ
      assets/fonts/work-sans/WorkSans-Hairline.otf
  18. バイナリ
      assets/fonts/work-sans/WorkSans-Italic.otf
  19. バイナリ
      assets/fonts/work-sans/WorkSans-Light.otf
  20. バイナリ
      assets/fonts/work-sans/WorkSans-LightItalic.otf
  21. バイナリ
      assets/fonts/work-sans/WorkSans-Medium.otf
  22. バイナリ
      assets/fonts/work-sans/WorkSans-MediumItalic.otf
  23. バイナリ
      assets/fonts/work-sans/WorkSans-Regular.otf
  24. バイナリ
      assets/fonts/work-sans/WorkSans-SemiBold.otf
  25. バイナリ
      assets/fonts/work-sans/WorkSans-SemiBoldItalic.otf
  26. バイナリ
      assets/fonts/work-sans/WorkSans-Thin.otf
  27. バイナリ
      assets/fonts/work-sans/WorkSans-ThinItalic.otf
  28. バイナリ
      assets/fonts/work-sans/worksans-italic-vf.ttf
  29. バイナリ
      assets/fonts/work-sans/worksans-roman-vf.ttf
  30. +0
    -0
      assets/images/labelize.png
  31. バイナリ
      assets/images/pause.png
  32. バイナリ
      assets/images/play.png
  33. +70
    -0
      assets/js/labelize.js
  34. +173
    -0
      assets/js/player.js
  35. +0
    -124
      assets/labelize.css
  36. +0
    -60
      assets/labelize.js
  37. バイナリ
      assets/pause.png
  38. バイナリ
      assets/play.png
  39. +53
    -64
      labelize.py
  40. +11
    -0
      labelize.yaml
  41. +5
    -1
      requirements.txt
  42. +51
    -0
      template.html

+ 20
- 2
README.md ファイルの表示

@@ -1,6 +1,6 @@
# Labelize # Labelize


Music album web page generator : 1 folder with music files + 1 cover image = 1 single page app with audio player
Music band web page generator : 1 folder with music files + images + 1 optional configuration file = 1 single page app with audio player


# Installation # Installation


@@ -11,10 +11,28 @@ $ pip install -r requirements.txt


``` ```


#Configuration

In a labelize.yaml file :

````
band: band name
images:
cover: my_cover_image.png
contact: my_contact_image.png
albums_section :
title: Album section tile
albums:
- year : 2019
title : my album title
- year : 2018
title : my album title

````
# Usage # Usage


``` ```
$ python labelize.py inputDirectory outputDirectory
$ python labelize.py [inputDirectory] [outputDirectory]
``` ```


# Credentials # Credentials


+ 102
- 0
assets/css/labelize.css ファイルの表示

@@ -0,0 +1,102 @@
@font-face {
font-family: "work-sans";
src: url('../fonts/work-sans/WorkSans-Regular.otf');
}

:root{
--footer-font-family : 'work-sans';
--pretty-margin: 0.5rem;
--main-color: red;
--secondary-color: rgb(0,42,255);
}

*{
margin: 0;
padding: 0;
}

body{
font-family: var(--footer-font-family);
font-size: 2rem;
letter-spacing: 0.1rem;
}

.point {
margin: 0px var(--pretty-margin);
}

.pipe {
margin: 0px calc(3 * var(--pretty-margin));
}

section{
height: 100vh;
}

section h2 {
font-size: 2rem;
}

section:nth-of-type(odd){
background-color: white;
color: var(--secondary-color);
}

section:nth-of-type(even){
background-color: var(--secondary-color);
color: white;
}

section.cover{
background : url(../images/cover.png) no-repeat center center;
background-color: var(--main-color);

}

section.albums{
background-color: black;
color:white;
display: flex;
flex-direction: column;
justify-content: center;
line-height: 200%;
}

section.albums > * {
padding-left: 10vw;
}

section.albums h2 {
padding-left: 20vw;
font-weight: normal;
}

section.albums ul {
list-style-type: none;
}

section.contact{
display : flex;
flex-direction: column;
justify-content: center;
align-items: center;
position :relative;

background : url(../images/contact.png) no-repeat center center;
background-color: var(--secondary-color);
color:white;

}


footer{
font-size: 0.92rem;
position: absolute;
width: 100%;
bottom: 0;
text-align: center;
}

.hidden{
display: none;
}

+ 108
- 0
assets/css/player.css ファイルの表示

@@ -0,0 +1,108 @@
:root{
--one-dpi: 72px;
--dd-blue: rgb(0,42,255);
}

.dd-player{
width: 25vw;
height: 100vh;
position:fixed;
top: 0px;
background-color: white;
right:0px;
color: black;
padding-top: var(--one-dpi);
padding-bottom: var(--one-dpi);
display: flex;
flex-direction: column;
justify-content: space-between;
}

.collapsed{
display: none;
}

.dd-player-switch{
position :fixed;
bottom: 0;
right: 0;
width: var(--one-dpi);
height:var(--one-dpi);
background-color: white;
cursor: pointer;
z-index:10;
}

.dd-player-switch.opened{
background-color: var(--dd-blue);
}

.dd-player h3 {
font-size: 1rem;
/*margin-top: calc(2 * var(--one-dpi));*/
margin: calc(var(--one-dpi) / 2);
/* margin-bottom : var(--one-dpi); */
}

.dd-player ul {
margin-left : calc(var(--one-dpi) / 2);
color: var(--dd-blue);
font-size: 1.5rem;
list-style-type : none;
}

.dd-player ul li img{
width:24px;
height:24px;
margin-right: 12px;
}

.playing{
font-weight: bold;
color : black;
}

.progress-wrap{
display:flex;
width: 100%;
justify-content: space-around;

}
.progress-wrap .time-info{
font-size:0.66rem;
display: flex;
justify-content: center;
/* align-items: center; */
}

progress{
display: inline;
/* margin: 0 calc(var(--one-dpi) / 2); */
/* max-width: calc(100% - var(--one-dpi)); */
height: 10px;
width:66%;

}



#play-button{
max-width: calc(var(--one-dpi) / 2);
max-height: calc(var(--one-dpi) / 2);
margin: calc(var(--one-dpi) / 2);
}

progress::-moz-progress-bar{
background-color: black;
}
progress{
background-color: #rgba(200,200,200,0.5);
}

.dd-player ul li, #play-button{
cursor : pointer;
}

#wrap-playlist{
flex: 1;
}

バイナリ
assets/fonts/noto-sans/NotoSans-Bold.ttf ファイルの表示


バイナリ
assets/fonts/noto-sans/NotoSans-BoldItalic.ttf ファイルの表示


バイナリ
assets/fonts/noto-sans/NotoSans-Italic.ttf ファイルの表示


バイナリ
assets/fonts/noto-sans/NotoSans-Regular.ttf ファイルの表示


assets/fonts/noto-sans/SIL Open Font License.txt → assets/fonts/work-sans/SIL Open Font License.txt ファイルの表示

@@ -1,4 +1,5 @@
Copyright 2012 Google Inc. All Rights Reserved.
Copyright (c) 2014-2015 Wei Huang (wweeiihhuuaanngg@gmail.com)



This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL

バイナリ
assets/fonts/work-sans/WorkSans-Black.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-BlackItalic.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-Bold.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-BoldItalic.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-ExtraBold.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-ExtraBoldItalic.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-ExtraLight.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-ExtraLightItalic.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-Hairline.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-Italic.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-Light.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-LightItalic.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-Medium.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-MediumItalic.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-Regular.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-SemiBold.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-SemiBoldItalic.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-Thin.otf ファイルの表示


バイナリ
assets/fonts/work-sans/WorkSans-ThinItalic.otf ファイルの表示


バイナリ
assets/fonts/work-sans/worksans-italic-vf.ttf ファイルの表示


バイナリ
assets/fonts/work-sans/worksans-roman-vf.ttf ファイルの表示


assets/labelize.png → assets/images/labelize.png ファイルの表示


バイナリ
assets/images/pause.png ファイルの表示

変更前 変更後
幅: 48  |  高さ: 48  |  サイズ: 225 B

バイナリ
assets/images/play.png ファイルの表示

変更前 変更後
幅: 48  |  高さ: 48  |  サイズ: 299 B

+ 70
- 0
assets/js/labelize.js ファイルの表示

@@ -0,0 +1,70 @@
import DedePlayer from './player.js';

window.addEventListener('DOMContentLoaded', (event) => {
const player = new DedePlayer(document.getElementById('player'));
})
//var current = undefined
//const progressMargin = 50;
//var progress = undefined;
//window.addEventListener('DOMContentLoaded', (event) => {
// progress = document.getElementById('player-progress');
// document.getElementById('player-progress').addEventListener('click', (e) => {
// if(current){
// let media = current.getElementsByTagName('audio')[0];
// media.currentTime = e.layerX * media.duration / progress.offsetWidth;
//
// }
// });
//
// let toggler = document.getElementById('player-toggler');
// toggler.setAttribute('title','afficher/masquer la liste des morceaux');
// toggler.addEventListener('click', (e) => {
// document.getElementsByTagName('ul')[0].classList.toggle('invisible');
// })
//});
//
//
//function togglePlay(src) {
// let media = src.getElementsByTagName('audio')[0];
// let icon = src.getElementsByTagName('img')[0];
// if (current){//stops current media and reset its play icon
// pause();
// }
// if(current != src){
// //sets current media icon and plays media
// icon.setAttribute('src','assets/pause.png');
// media.play();
// progress.max = Math.floor(media.duration);
// current = src;
// document.getElementById('time-info').style.visibility = 'visible';
// }
// else{
// current = undefined;
// }
//}
//
//function pause(){
// current.getElementsByTagName('audio')[0].pause();
// current.getElementsByTagName('img')[0].setAttribute('src','assets/play.png');
// document.getElementById('time-info').style.visibility = 'hidden';
//}
//
//function updateProgress(media){
// progress.value = Math.floor(media.currentTime);
// document.getElementById('time-info').innerHTML =
// prettyDuration(media.currentTime) + ' / ' + prettyDuration(media.duration);
//}
//
//function prettyDuration(duration) {
// let sec = Math.floor( duration );
// let min = Math.floor( sec / 60 );
// min = min >= 10 ? min : '0' + min;
// sec = Math.floor( sec % 60 );
// sec = sec >= 10 ? sec : '0' + sec;
// return min + ':' + sec;
//}
//
//function togglePlayer(playerId, dpiId){
// document.getElementById(playerId).classList.toggle('hidden');
// document.getElementById(dpiId).classList.toggle('clicked');
//}

+ 173
- 0
assets/js/player.js ファイルの表示

@@ -0,0 +1,173 @@
export default class DedePlayer{

constructor(container){
this.currentAudio = null;
this.playing = false;
this.playerContainer = document.createElement("div");
this.container = container;
this.playerContainer.classList.add('dd-player');
this.switcher = document.createElement("div");
this.switcher.classList.add('dd-player-switch');
this.playerContainer.classList.add('collapsed');
//document.body.appendChild(this.container);
document.body.appendChild(this.switcher);

this.switcher.addEventListener('click', event => {
this.playerContainer.classList.toggle('collapsed');
this.switcher.classList.toggle('opened');
});

let title = document.createElement("h3");
//title.innerHTML = playList.title;
title.appendChild(document.createTextNode(this.container.dataset.title));

this.addProgressBar();
// this.container.appendChild(title);
this.bindAudioTags();
this.addPlayButton();
//console.log(Math.floor(this.currentAudio.duration));

// let playerLinks = document.querySelectorAll('.dd-player-link');
// let self = this;
// playerLinks.forEach(function(pl){
// pl.addEventListener('click', (e) => {
// self.container.classList.toggle('collapsed');
// self.switcher.classList.toggle('opened');
// })
// });

let wrap = document.createElement("div");
wrap.setAttribute('id', 'wrap-playlist')
this.container.parentElement.appendChild(this.playerContainer);
this.playerContainer.appendChild(title);
this.playerContainer.appendChild(wrap);
wrap.appendChild(this.container);

};

addProgressBar(){
this.progressBar = document.createElement("progress");
this.progressBar.setAttribute('value', 0);
this.startTimeInfo = document.createElement('div');
this.endTimeInfo = document.createElement('div');
let progressWrap = document.createElement("div");
this.startTimeInfo.innerHTML = "00:00";
this.endTimeInfo.innerHTML = "00:00";
progressWrap.appendChild(this.startTimeInfo);
progressWrap.appendChild(this.progressBar);
progressWrap.appendChild(this.endTimeInfo);
this.startTimeInfo.classList.add('time-info');
this.endTimeInfo.classList.add('time-info');
progressWrap.classList.add('progress-wrap');
this.playerContainer.append(progressWrap);
let self = this;
this.progressBar.addEventListener('click', (e) => {
if(self.currentAudio){
self.currentAudio.currentTime = Math.floor(((e.layerX - self.progressBar.offsetLeft) * self.currentAudio.duration) / self.progressBar.offsetWidth);
self.progressBar.value = Math.floor(self.currentAudio.currentTime );
}
});


}


addPlayButton(){
this.playButton = document.createElement("img");
this.playButton.setAttribute('src','assets/images/play.png');
this.playButton.setAttribute('id','play-button');
let wrap = document.createElement("div");
wrap.append(this.playButton);
this.container.append(wrap);
let self = this;
this.playButton.addEventListener('click', event => {
self.playing = !self.playing;
if(self.playing){
self.currentAudio.play();
self.currentAudio.parentElement.classList.add('playing');
self.progressBar.setAttribute('max', Math.floor(self.currentAudio.duration));
self.endTimeInfo.innerHTML = self.formatDuration(self.currentAudio.duration);
this.playButton.setAttribute('src','assets/images/pause.png');
}
else{
self.currentAudio.pause();
self.currentAudio.parentElement.classList.remove('playing');
this.playButton.setAttribute('src','assets/images/play.png');
}
})
}

bindAudioTags(){
//let listElement = document.createElement("ul");
let liTags = this.container.querySelectorAll('li')
let self = this;
let i = 0;
liTags.forEach(function(itemElement){
// //let playBtn = document.createElement("img");
// //playBtn.setAttribute('src','images/icons/play.png');
// let itemElement = document.createElement("li");
// //itemElement.appendChild(playBtn);
// itemElement.appendChild(document.createTextNode(track.title));
// listElement.appendChild(itemElement);
// let audioElement = document.createElement('audio');
// audioElement.setAttribute('src',track.src);
let audioTag = itemElement.querySelector('audio')

audioTag.addEventListener('timeupdate', (event) => {
self.audioTimeUpdate(audioTag);
});
audioTag.addEventListener('ended', (event) => {
self.audioEnded(i);
})

//itemElement.appendChild(audioElement);
audioTag.setAttribute('id','track-'+i);
if(i === 0)
self.currentAudio = audioTag;
itemElement.addEventListener('click', event => {
let items = self.container.getElementsByTagName('li');
for(let i = 0; i < items.length; i++){
items[i].classList.remove('playing');
}
if(self.currentAudio)
self.currentAudio.pause();
audioTag.play();
self.playButton.setAttribute('src','assets/images/pause.png');
self.playing = true;
itemElement.classList.add('playing');
self.currentAudio = audioTag;
self.progressBar.setAttribute('max', Math.floor(self.currentAudio.duration));
self.endTimeInfo.innerHTML = self.formatDuration(self.currentAudio.duration);
self.progressBar.setAttribute('value', 0);
});

i++;

});



}

audioTimeUpdate(audioElt){
this.progressBar.value = Math.floor(audioElt.currentTime);
this.startTimeInfo.innerHTML = this.formatDuration(audioElt.currentTime);
}

audioEnded(n){
let audios = document.getElementsByTagName('audio');
let next = n == audios.length - 1 ? 0 : n + 1;
this.currentAudio.pause();
this.currentAudio.currentTime = 0;
this.currentAudio = document.getElementsByTagName('audio')[next];
this.currentAudio.parentElement.click();
}

formatDuration(time){
let s = parseInt(time% 60);
let m = parseInt((time / 60) % 60);
return (m < 10 ? ('0'+m) : m) + ':' + (s < 10 ? ('0'+s) : s);
}


}

+ 0
- 124
assets/labelize.css ファイルの表示

@@ -1,124 +0,0 @@
@font-face {
font-family: "NotoSans";
src: url(./fonts/noto-sans/NotoSans-Regular.ttf);
}

:root {
--main-bg-color: rgba(255,255,255,0.7);
}

*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
html{
font-family: NotoSans;
color: black;
}
html, body{
width: 100vw;
height: 100vh;
background-color: black;
}

body{
display: flex;
align-items: center;
justify-content: center;
}

.track-list{
width: 100vh;
height: 100vh;
background-image: url(../cover.jpg);
background-size: cover;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

ul.invisible{
display: none;
}

ul{
position: fixed;
right:0px;
top:0px;
padding-top: 30px;
list-style-type: none;
background-color: var(--main-bg-color);
height: 100vh;
font-size: 0.75rem;
}

div#player-toggler{
position: fixed;
top: 0px;
right:0px;
margin-top:2px;
margin-right: 2px;
z-index: 10;
cursor: pointer;
}

li{
/*background-color: var(--main-bg-color);*/
padding: 2px;
}
li{
margin-top:2px;
display: flex;
justify-content: center;
align-items: center;
}

button{
background-color: rgba(0,0,0,0);
border: none;
margin-left: 5px;
cursor: pointer;
}

div#player-toggler > img{
width: 24px;
height: 24px;
}
button img{
width: 16px;
height: 16px;
}

progress::-moz-progress-bar {
background-color: black !important;
}
#player-progress{
position: fixed;
left:0;
top:0;
height: 1vw;
width: 100vh;
background-color: var(--main-bg-color);
border: none;
border-top:2px solid var(--main-bg-color);
border-bottom:2px solid var(--main-bg-color);
cursor: pointer;
transform: rotate(90deg);
transform-origin: top left;
margin-left: 1vw;
/* margin-top:calc(50vh - 0.5vw);
margin-left:0; */
}

#time-info{
visibility: hidden;
position: fixed;
bottom: 2px;
left: 1%;
padding-left: 2px;
color:white;
font-size: 0.6rem;
}

+ 0
- 60
assets/labelize.js ファイルの表示

@@ -1,60 +0,0 @@
var current = undefined
const progressMargin = 50;
var progress = undefined;
window.addEventListener('DOMContentLoaded', (event) => {
progress = document.getElementById('player-progress');
document.getElementById('player-progress').addEventListener('click', (e) => {
if(current){
let media = current.getElementsByTagName('audio')[0];
media.currentTime = e.layerX * media.duration / progress.offsetWidth;

}
});

let toggler = document.getElementById('player-toggler');
toggler.setAttribute('title','afficher/masquer la liste des morceaux');
toggler.addEventListener('click', (e) => {
document.getElementsByTagName('ul')[0].classList.toggle('invisible');
})
});


function togglePlay(src) {
let media = src.getElementsByTagName('audio')[0];
let icon = src.getElementsByTagName('img')[0];
if (current){//stops current media and reset its play icon
pause();
}
if(current != src){
//sets current media icon and plays media
icon.setAttribute('src','assets/pause.png');
media.play();
progress.max = Math.floor(media.duration);
current = src;
document.getElementById('time-info').style.visibility = 'visible';
}
else{
current = undefined;
}
}

function pause(){
current.getElementsByTagName('audio')[0].pause();
current.getElementsByTagName('img')[0].setAttribute('src','assets/play.png');
document.getElementById('time-info').style.visibility = 'hidden';
}

function updateProgress(media){
progress.value = Math.floor(media.currentTime);
document.getElementById('time-info').innerHTML =
prettyDuration(media.currentTime) + ' / ' + prettyDuration(media.duration);
}

function prettyDuration(duration) {
let sec = Math.floor( duration );
let min = Math.floor( sec / 60 );
min = min >= 10 ? min : '0' + min;
sec = Math.floor( sec % 60 );
sec = sec >= 10 ? sec : '0' + sec;
return min + ':' + sec;
}

バイナリ
assets/pause.png ファイルの表示

変更前 変更後
幅: 640  |  高さ: 640  |  サイズ: 17 KiB

バイナリ
assets/play.png ファイルの表示

変更前 変更後
幅: 640  |  高さ: 640  |  サイズ: 19 KiB

+ 53
- 64
labelize.py ファイルの表示

@@ -1,67 +1,33 @@

import eyed3 import eyed3
import os import os
import sys import sys
import shutil import shutil
from html_writer import Html

#TracksDir class definition
class TracksDir:
def __init__(self, trackFiles):
self.trackFiles = trackFiles

#HTML Output
def toHTML(self):
head = Html()
head.self_close_tag('meta', attributes=dict(charset='utf-8'))
head.self_close_tag('link', attributes=dict(href='assets/labelize.css',rel='stylesheet'))
body = Html()
trackNumber = 0
with body.tag('div',classes=['track-list']):
#body.tag_with_content('Track List', name='h2')
with body.tag('div',attributes=dict(id='player-toggler')):
body.self_close_tag('img', attributes=dict(src='assets/labelize.png'))
with body.tag('ul') as list:
for t in self.trackFiles:
trackNumber = trackNumber + 1
trackId = 'track-' + str(trackNumber)
audiofile = eyed3.load("build/" + t)
with body.tag('li') as li:
print(audiofile.tag.title)
li += str(audiofile.tag.title or 'untitled')+ ' - '
li += str(audiofile.tag.album or 'untitled')+ ' - '
li += audiofile.tag.artist
with body.tag('button',attributes=dict(onclick="togglePlay(this)")):
body.self_close_tag('img', attributes=dict(src='assets/play.png'))
with body.tag('audio', attributes=dict(src=t, id=trackId,
ontimeupdate="updateProgress(this)")) as audio:
audio+="Your browser does not support the audio element"

# with body.tag('canvas',attributes=dict(id='player-progress')) as canvas:
# canvas += "player's progress bar"
with body.tag('progress',attributes=dict(id='player-progress',value='0')) as canvas:
canvas += "player's progress bar"
with body.tag('div',attributes=dict(id='time-info')) as timeInfo:
timeInfo += '00:00'
with body.tag('script', attributes=dict(src='assets/labelize.js')) as script:
script+=""#script tag is not added without that trick

return Html.html_template(head, body).to_raw_html(indent_size=2)
import yaml
from mako.template import Template


# TracksDir class definition
class Album:
def __init__(self, track_files):
self.trackFiles = track_files



# script usage function # script usage function
def usage(): def usage():
print('USAGE : labelize.py [inputDirectory] [outputDirectory]') print('USAGE : labelize.py [inputDirectory] [outputDirectory]')



# script beginning # script beginning
arguments = len(sys.argv) - 1 arguments = len(sys.argv) - 1
if(arguments != 2):
if arguments != 2:
usage() usage()
sys.exit(2) sys.exit(2)


inputDirectory = sys.argv[1]
outputDirectory = sys.argv[2]
input_directory = sys.argv[1]
output_directory = sys.argv[2]



def copyDirectory(src, dest):
def copy_directory(src, dest):
try: try:
shutil.copytree(src, dest) shutil.copytree(src, dest)
except shutil.Error as e: except shutil.Error as e:
@@ -69,23 +35,46 @@ def copyDirectory(src, dest):
except OSError as e: except OSError as e:
print('Directory not copied. Error: %s' % e) print('Directory not copied. Error: %s' % e)


#removes existing build directory if exists
if os.path.isdir(outputDirectory):
shutil.rmtree(outputDirectory)


#copies source files in the build directory
copyDirectory(inputDirectory, 'build')
# removes existing build directory if exists
if os.path.isdir(output_directory):
shutil.rmtree(output_directory)
#
# copies source files in the build directory
copy_directory(input_directory, output_directory + '/audio')


#copies assets in the build directory
copyDirectory('assets', outputDirectory + '/assets')
# copies assets in the build directory
copy_directory('assets', output_directory + '/assets')


for root, dirs, files in os.walk(inputDirectory):
trackFiles = []
for f in files:

with open('labelize.yaml') as f:
data = yaml.load(f, Loader=yaml.FullLoader)
title = data['band']
cover_img = data['images']['cover']
contact_img = data['images']['contact']

shutil.copyfile(input_directory + '/' + cover_img, output_directory + '/assets/images/cover.png');
shutil.copyfile(input_directory + '/' + contact_img, output_directory + '/assets/images/contact.png');

track_files = []
for root, dirs, files in os.walk(input_directory):
for f in sorted(files):
if f.lower().endswith(('.mp3', '.wav', '.ogg')): if f.lower().endswith(('.mp3', '.wav', '.ogg')):
trackFiles.append(f)
track_files.append(f)
print(f)

# td = TracksDir(trackFiles)
# f = open(output_directory + "/index.html", "w+")
# f.write(td.to_html())
# f.close()
my_template = Template(filename='template.html')
f = open(output_directory + "/index.html", "w+")

# Write template data to the file created
f.write(my_template.render(
title=title,
tracks=track_files,
albums_section=data['albums_section']))


td = TracksDir(trackFiles)
f = open(outputDirectory + "/index.html","w+")
f.write(td.toHTML())
f.close()
# Close file
f.close()

+ 11
- 0
labelize.yaml ファイルの表示

@@ -0,0 +1,11 @@
band: Clou
images:
cover: image.png
contact: image2.png
albums_section :
title: CLOU albums | with LABELAR
albums:
- year : 2019
title : p
- year : 2018
title : x

+ 5
- 1
requirements.txt ファイルの表示

@@ -1,4 +1,8 @@
eyeD3==0.8.10
eyeD3==0.8.12
html-writer==1.1.1 html-writer==1.1.1
Mako==1.1.2
MarkupSafe==1.1.1
pkg-resources==0.0.0
python-magic==0.4.15 python-magic==0.4.15
PyYAML==5.3.1
six==1.12.0 six==1.12.0

+ 51
- 0
template.html ファイルの表示

@@ -0,0 +1,51 @@
## -*- coding: utf-8 -*-
<!DOCTYPE html>

<html lang="fr">
<head>
<meta charset="utf-8">

<title>${title}</title>
<meta name="description" content="dedemo">
<meta name="author" content="dede.space">
<link rel="stylesheet" href="assets/css/player.css">
<link rel="stylesheet" href="assets/css/labelize.css">
</head>

<body>
<section class="cover">

<!-- <img src="images/CLOU_Icono-1.png"/> -->
</section>
<!-- <section class="dates">-->
<!-- <h2><span class="scaps">${title}</span> live</h2>-->
<!-- </section>-->
<section class="albums">
<h2>${albums_section['title']}</h2>
<ul>
% for a in albums_section['albums']:
<li>${a['year']} : ${a['title']}</li>
% endfor
</ul>
</section>

<section class="contact">
<span>contact<span class="point">@</span>clou<span class="point">.</span>space</span>
<footer class="flex-center">
dede<span class='point'>.</span>space<span class='pipe'>|</span>2019
</footer>
</section>

<ul id="player" data-title="Album title">
% for t in tracks:
<li>${loop.index}<audio src="audio/01.mp3" id="track-${loop.index}"></audio></li>
% endfor
</ul>


<script type="module" src="./assets/js/labelize.js"></script>

</body>
</html>

<!---nav footered-screen-->

読み込み中…
キャンセル
保存