🎤 Kashi
🎯 Goal
This project is a dependency-free library that aims to provide a way to correctly read, format, structure, and display song lyrics.
📜 Features
- [x] 🎵 Process and list song lyrics in .lrc files
- [x] 💪 Supports both directly inputting the .lrc file and a URL that returns it
- [x] ✉️ Implements the Observer pattern and emits events at each step of the process whenever something changes
- [x] ✏️ Allows you to enter custom text when the lyrics line is empty
- [ ] 🎤 Synchronizes the lyrics with the music that is playing
- [ ] 🎩 Supports multiple lyrics for the same song (useful to keep track of the original lyrics and their translation)
- [ ] 🧞 Supports the Walaoke extension#Walaoke_extension)
- [ ] 🕖️ Supports the A2 extension#A2extension(Enhanced_LRC_format))
🎨 How to use it in my project?
🙌 Classic scripts
The project is also exported using UMD, which means that all variables and classes such as the Kashi
class is exposed globally, and can be used in any script imported after the library.
Note: You should change
X.Y.Z
to the library version number according to your needs, this is just an example. It is recommended to always use the latest version.It is recommended that you pin to the latest stable version of the lib. However, if you always want to use the latest version, you can also use
latest
instead of a predefined version number. Be careful though, breaking changes may be introduced and your project may need to adapt to the changes.
<!DOCTYPE html>
<html>
<head>
<!-- ... -->
<script src="https://unpkg.com/kashi@X.Y.Z/kashi.js" defer></script>
<!-- ... -->
</head>
<body>
<div id="kashi"></div>
</body>
</html>
"use strict";
// Using the file or using a url, both works fine
new Kashi({
// url, // Public link that returns the file when a GET request is made OR...
file. // Loaded from an input[type="file"] or anywhere else
container: document.getElementById("kashi"),
});
📦️ ES6 Modules
The HTML is very similar to the classic scripts version, just change the .js
extension to .mjs
(and maybe will be necessary to adds a type="module"
too), which will result in something similar to this:
Note: Please read the previous section to get the details involved in importing and choosing a package version, they are the same here.
<script
src="https://unpkg.com/kashi@X.Y.Z/kashi.mjs"
type="module"
defer
></script>
import { Kashi } from "kashi";
// Usage is essentially the same as in the previous section
// Using the file or using a url, both works fine
new Kashi({
// url, // Public link that returns the file when a GET request is made OR...
file. // Loaded from an input[type="file"] or anywhere else
container: document.getElementById("kashi"),
});
⚛️ React
Install the lib using your favorite package manager.
npm install kashi
Since the library was designed primarily to be used with vanilla JS, a helper component needs to be created to encapsulate Kashi's behavior and make it simple to reuse throughout the application.
Note: There is TypeScript support, and even if your project doesn't use the JS superset, it should help VSCode and other editors provide autocomplete/code suggestions.
import { useEffect, useRef } from "react";
import { Kashi, KashiProps } from "kashi";
// Example using Vite, React and TypeScript
export const KashiWrapper = (props: KashiProps) => {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (ref.current) {
new Kashi({
...props,
container: ref.current,
});
}
return () => {
// Required to avoid duplication when React is in Strict Mode
if (ref.current) {
ref.current.innerHTML = "";
}
};
}, [ref.current]);
return <div className="kashi-wrapper" ref={ref} />;
};
🧐 Constructor properties
You must pass some properties to Kashi to define what lyrics display and where. Here are its specifications:
Property | Type | Default value | Is required? | Description |
---|---|---|---|---|
file |
Blob (or File ) |
- | No | Lyrics file |
url |
string |
- | No | Lyrics url |
container |
HTMLDivElement |
- | Yes | Element where the lyrics will be inserted |
emptyLineText |
string |
🎝 |
No | Custom text for empty lines of the lyrics |
Neither
file
norurl
are “mandatory”, but at least one of these properties must be specified, otherwise an error will be thrown.
👾 Generated HTML structure
The div#kashi
represents the container
passed to Kashi
where the song lyrics will be inserted.
Each line of lyrics present in the lrc file will be wrapped by a <p></p>
tag and inserted into the container
.
Here's an example:
<div id="kashi">
<!-- ... -->
<p>Binkusu no sake wo todoke ni yuku yo</p>
<p>Umikaze kimakase namimakase</p>
<p>Shio no mukou de yuuhi mo sawagu</p>
<p>Sora nya wa wo kaku tori no uta</p>
<!-- ... -->
</div>
📂 Methods and attributes
The instance generated by Kashi
has some public methods and attributes that can be used to query or change properties on the fly.
Name | Type | Description |
---|---|---|
url |
Attribute | Returns the url from the current lyrics if it was fetched from a link |
file |
Attribute | Returns the file from the current lyrics |
emptyLineText |
Attribute | Returns the default text set for empty lines |
setUrl |
Method | Function capable of changing the current lyrics file by passing the url of the new file |
setFile |
Method | Function capable of changing the current lyrics file by passing the the new file |
setEmptyLineText |
Method | Function capable of changing the text defined for empty lines |
subscribe |
Method | Function capable of defining a callback to be executed when a given event is triggered |
unsubscribe |
Method | Function capable of making a callback to stop listening to an event |
notify |
Method | Function capable of triggering an event |
🍾 Events
When creating a new instance using Kashi
you will have access to the subscribe
, unsubscribe
and notify
methods, these methods can be used respectively to listen for an event, stop listening for an event and manually trigger an event. Below is the list of events triggered internally:
Event | Data | Trigger |
---|---|---|
urlSet |
{ url: string } |
When instantiating by informing url or calling the setUrl method |
fileSet |
{ file: Blob } |
When instantiating or calling the setFile method (when calling the setUrl method the file will be fetched and the setFile method called) |
emptyLineTextSet |
{ emptyLineText: string } |
When instantiating by informing emptyLineText or calling the setEmptyLineText method |
lyricLinesUpdated |
{ lyricLines: string[] } |
When inserting/updating lyrics in HTML |
🤔 How do I run the project on my machine?
The first step is to clone the project, either via terminal or even by downloading the compressed file (.zip). After that, go ahead.
🛠️ Requirements
✨ Running the project
With the dependencies properly installed, still in the terminal, run npm start
.
Create a simple demo project using vanilla HTML/JS and use the files in the dist
folder for testing.
You can also create a demo project using React and use npm link.
🎉 If everything went well...
Now you are running the project beautifully!
✏️ License
This project is under the GPL v3 license. See the LICENSE for more information.
Made with 💙 by lucasmc64 👋 Get in touch!