Ritualia
- 42 Devlogs
- 148 Total hours
A music recommendation and playback system focused on algorithmic fugue and repertoire expansion open source and totally free! Select an genre + emotion and get a music, description, interesting facts and Fun!
A music recommendation and playback system focused on algorithmic fugue and repertoire expansion open source and totally free! Select an genre + emotion and get a music, description, interesting facts and Fun!
I configured an oracle cloud vm with ubuntu to host my website 24/7, that was because nest wasnt working in a while. Im running it at a local IP with http only, i will configure https today and maybe an domain, the IP is http://164.152.55.252, notice that some browsers may block you from accessing and http website.
UPDATE AFTER THE DEVLOG: I put an domain using duck dns: http://ritualia.duckdns.org
I had absolutely not a single knowledge about oracle cloud vm, so configuring it was an hell. Sometime my internet stopped working so i had to use my smartphone, this lead me to configuring an invalid ssh key and i had do configure everything from scratch, i spent 5 hours configuring everything, but that was ssh and wasnt tracked. But now everything is working fine.
This vm is a 24/7 entire OS (Virtual Machine) that has some good free plans, without any cold start.
Stardance now will have one more mount!!!!!! I still has roughly 40 hours of deep development to do after this ship, i will love to finish that in stardance!
Now there is guides to help the user install for ubuntu, arch and windows.
Notice that im a linux user and my pc is weak, so i could not test it on another operational system. Also the guide is in portuguese (all of them), please use your browser built-in translator or any of them to read if u dont understands portuguese
I could test it on another linux distro, but i would have to go through all the install steps. Also i cannot try installing windows because it normally wipe out another OS installed on the same disc (i know that it just replaces the bootloader) and using a VM was not possible due to the amount of RAM and the processor that i have.
Now the system has a new navigation system that allow users to navigate with just the keyboard! (The video was with just the keyboard)
Why not? It was meant to improve the accessibility for users without mouse, or any another problem and because i was tired of having to use the mouse to debug something.
Again with a lot of pain, the feature itself was easy but i had to fix some errors that went unnoticed, so it took more time. The feature detects when the user press a key and do an action based on wich key was.
The accessibility was easy to get 100, but the metrics at lighthouse dont give all what the users will need, i had to think about the website usage and how would be the easiest way for the user.
The accessibility went from nearly 69 to 100!
Now i will work on the best practices!
Update after the devlog: Nearly every metric is already maxed out lol, i will ship it very soon!
Now the logo z-index is lower, that is because the logo was ‘eating’ the click in more important elements.
Also i did a small change at the cover-flow, that change fix the bug of the scroll at the element sudently stoping when at a certain position.
The copa script had some old references to images that were leading to bugs, i changed it.
I already finished it in the past devlog, i was just checking if there was anything worth improving, but everything is working fine and now is time to improve acessibility.
Most of the logged time was me trying to improve more some metrics at the lighthouse, but the work was too much for anything that is already good, so i decided to stop before i started focusing too much in it.
Now the youtubeHelpers checks if the youtube API is ready before sending commands.
Sometimes the API maybe is not finished yet, that was leaving an untreated error that was braking the entire website.
With a lot of pain and suffer. I thought “Oh hey, that will be a 15 minutes fix” - i spent 1 HOUR FIGHTING with the iframe itself, nothing was working and at some point i started thinking that even the API of YOUTUBE wasnt working, even the most basic function that should be triggered when the youtube finished the loading wasnt beeing activated, even the console.log(“Api READY!”) wasnt working, even when it worked it wasnt working well, the variable of the player was a promise and not the result. At the end i shut down my PC, defeated, without any energy left, with just hope that in the next day (this) that would be fixed (if not i was planning to ignore and make it a feature “Easter egg, if u dont join the website for a while it will not load!”.
The problem here was just the position were the iframe api was in the HTML, it was being loaded before the helper script, so the helper was not there to check if it the iframe was ready or not, the fix was just move it a little down.
It was just an promise, if the function checks that the iframe isnt available it await for it to be available. The check if it was available use the onYoutubeIframeAPIReady, easy easy (except for all the suffer that i went into).
I fixed the error that were happening when the cover had a certain amount of elements.
The fix itself was very easy to do, but doing it in a readable or without using 10 lines of code (i want things concise) was way harder than i expected. So i spent this entire time trying different ways to do it, each of them making everything worse.
The bug were with less than 14 elements, the script were calculating the first and last element index, it happened that these elements were behind the screen focus. Why? Because the values that the system was using were leaving these values, so i had to fix the way it was calculating things.
Now the loading at the mutationObserver is finished, it finally loads or unloads the images that should be (or not) loaded!
The new observer is way faster, because it can detect the image way before it enters the screen, loading it before and having more time to do it. Also the system loads just a maximum of images (with the configs that i put it is 13), so it will not fry an cellphone.
The loading part was easy to do, i already done it before in the past observer (intersectionObserver), so i just had to pass the old code to the new part. But when the cover-flow element dont got atleast 13 elements the mutationObserver code breaks completely! Im still pondering how to solve it, when i do i will post about!
The old method was slow even with a good internet connection, because it was loading the images just when the element was already in the screen, leaving to a perceptive delay for the user and a blank image to the user. Also i thought about creating an observer from scratch (maybe i was a little off my ideas, because that was insane), but the browser already had exactly what i wanted (the mutationObserver)
While i was trying to sleep i thought about a system that fill the cover-flow with a maximum of images (like 10, or 13, or the code decides) at the DOM, using less memory to run. That system will free a lot of memory based on how many cards the cover-flow have. But that will have noticeable effects just with a lot of elements and probably would be hard to develop, maybe i will do in next updates.
Im leading to the shipping, so i will improve metrics about the lighthouse, improve the readme and post it.
Now, instead of an intersectionObserver, the system use a mutationObserver that monitors the angle of the cylinder itself. With that the loading of the images will be insanely better, faster and user-friendly. Now the changes in the cover-flow is observed at the cylinder angle, not at each card. There was some problems in the journey like, for some reason, unexpected cards being loaded or not, the loading script at the observer dont triggering at all (that was caused by the speed of the observer) and an insane amount of cards being triggered at the same time (i still did not figured out why, but that isnt ‘harmful’). But man, i had to be creative here and remember about some concepts like concurrent programming, buffer / queue and apply some delays (because the mutationObserver is insanely fast and can trigger every millisecond). That all was meant to decrease the speed of the mutationObserver, because it was triggering with the most small change in the cylinder, so i made it trigger just when an expected amount of movement was made.
The red/yellow collor is for me to visualize the loading state, it is just for debug
The code isnt finished, i still need to implement the loading part, for now i just implemented the observer and basics of the loading part
Now the cover-flow has an observer that checks the position of the images and changes it styles based on that, so the images that the user is seeing is loaded while the others is hide.
It still has some bugs and space for improvements that im still figuring out how to solve, like the image loading too late on the screen or, in slow internet connections, the image takes too long to load.
Most of these bugs are because the observer (an intersectionObserver) was designed for 2d contexts, not 3d (that were and still is an giant problem to solve). For this reason i was thinking about creating an observer from scratch in C++ that can work better in my 3d element, but the overhead would be high so im trying to solve in other ways before that.
The feature was made using fetchPriority, contentVisibility and src (the system add the source just when the image is near the screen).
OBS: I found about MutationObserver after this post, maybe i will use that instead of insersectionObserver. Oh man, at least if had found about this before… Aaaaaahhhhh i spent 9 hours in that, but at least a Lot of the new logic will be used. Anyway, lets cook
Now the script observe the card elements at the cover-flow component, classify their position and changes it visibility based on that.
Im using an IntersectionObserver to observe every card, but it was designed to observe the position of 2d elements, so i had to figure out how to make it work well in an 3d element. The way it works is when the observe activates (it basically means that some card is in the range to load) it get the card info (like position and angle) and changes it visibility state based on that. Simple, right? No, it was a headache for the start to the top, nearly 4 hours of what i did was to fix the fact that it was meant for 2d. The observer were activating for cards that were in the back of the element, so i had to classify the card position into back or front by using its angle.
But if i tried to use the card angle without anything else the script would broke (and did for 3 hours until i realized how to fix), so i had to use an second angle which is 360 - cardAngle (the 360 is the angle of an circle), so this new angle is based on the circle end while the other is based on the circle start.
But the system still broke, because at some point one of these values would become negative and makes the if that classify the elements fail. The fix was using the absolute value in the if (it took 1 hour until i figured that; oh i were so happy when it worked).
To improve the performance, so the browser will just load what is really important and not 50 images that the user cant even see.
All that work definitely improved a lot my logic thinking and for the first time i used the truth table well.
Now i just need to use the new code to change more the style of the images that are not in the screen.
I did not deleted the code that i wrote in the past devlog, it was used in the new code to select how many images should be loaded in the same time.
** The first video is the result, the others is some problems that i had **
Now the system selects some images that needs to be shown faster than the others and making them load with priority. It was made by selecting the images that the user is seeing and defining some params like fetchPriority = "high" and decoding="sync", the other images have the params: decoding="async"; loading="lazy"; contentVisibility="auto";. With that config the LCP went from 2.4s to 0.5s. Also it loads the image in the start and dont change that config again, so the browser will be lazy while downloading these images. The problem is: only the first images are chosen as high priority, but their positions will be changed while the configs stays the same, that makes the browser lazy while loading them and makes the runtime performance became worse.
To fix that i found about IntersectionObserver, that are meant to solve the problem of updating the images position fast. It was not applied yet, i found about it like 1 hour ago.
I am improving the way that the website create and downloads the images, the main reason is to make the user see something faster. Before the system were doing 2 main things:
8.63s to 6.43s, the test was made with 2200 elements (Yeah ik, it is a lot and normally it isnt that much, but i had to see how they were holding with more than 22 items).Also i fixed a bug that passed unnoticed while improving the responsiveness: At some point of images the visibility of the elements broke, that was because the perspective (what makes the 3D perspective of the component, and makes it visible with 3D effects) was based on the screen size, not the elements itself. What was the problem in that: Each element takes a size in the screen ‘makes the circle that shows the element be more and more near of our point of view’ (i cant explain it any better, search what is ‘perspective in an 3d element at HTML’ ). While it was approaching our point of view (POV), our POV were exactly at the same position (based on the screen size), so at some point the circle perspective would pass the POV and we would be unable of seeing it well. Now it is based on the elements: The 3d elements were basically a circle, i just used the diameter to change the perspective based on it.
TODO: Maybe i lowered the image quality too much… I will fix it in the next updates.
Also i were trying to improve the font settings to improve the performance, but that wast working so i decided to move on to this because it was more critical (took a while for me to jump to this, maybe like 2 hours trying and trying values in the font settings).
i am also working in a way to load the images in parallel, with that it will take way less time
(I didnt known about LCP before so i spent a while figuring out the way it works).
After finishing the improvements in the responsiveness, now i decided to improve the performance. I used lighthouse to get insights (i learned about it in an tiktok video) and figured out that the images size were too high (were an png of 1280x1280px), so i saw more about that in the page: https://developer.chrome.com/docs/performance/insights/image-delivery (an link that google lighthouse gave).
With that i saw how to decrease the size while staying with quality, i reached up to the sharp-cli tool, that makes the work of resize, convert and compress the image for me. The command used was that:
npx sharp-cli -i *.png -o ./output resize 320 -f avif -q 50 --effort 6 --smartDeblock --preset photo
The 320 is the size that i want it to be at the end, i got that value by seeing what was the computed value (the value that is being used in the website) in an high resolution pc (not the most higher one, the high but normal pc) with the resolution of 2500x1714px.
With this simple changing the image went from 2mb to 40Kb! Nearly 100% decrease, and take in mind that there is more than one img, so the change were even higher.
Also i created 5 different images: 320px, 480px, 640px, 960px e 1280px. With them the browser can choose which one is better for each device. With these changes i went from 35 points of performance to 59.
Ah that took a while, but finally it is fully responsive. Now the description at the player UI resizes based on the screen size and active a scroll behaviour when need, also i did some minor change at the emotionDrum perspective to make it show more emotions at the same time, removed the padding in the arrows at the emotionDrum so they will have more space and fixed an error in the genre drum that was making it perspective broke.
After all these devlogs i improved how i make a code responsive.
Now the buttons that you use to select the emotion are in the same side as the div that displays the emotion, so they dont fight for space anymore. This change is meant to fix the low size of the items in screens that are too small, in the new way we have more free space to display the emotions, there is not much to say.
I did some minor changes in the size of some items at the player area, now they are easier to read! (I increased the size of some items)
Im nearly finishing the workings on the responsiveness. Now the entire player screen is responsive and do not breaks the texts anymore (except for the description area), also the buttons that show you the next screen (the ones that displays ‘player’ and ‘generos’) are responsive too, the music queue is working perfectly fine, and the area that is used to select an emotion is nearly responsive too, it just needs some adjusts in the two buttons that change the current emotion because they become too small and uses a lot of space when the screen is too small, after that this screen will be finished.
It is taking a really long time, the fact of how many different screen sizes exists makes it harder to finish, but now there is times that i even cannot see if i changed the resolution in some areas, because the system looks the same. I spent quite a while testing different resolutions and combinations of size, i didnt even noticed that i where 6 hours here, but now ik more about css (things like container-type + container based sizes and more ways to set the size of an text)
The video shows how it is now, if u want to see the before just checks the past devlog.
Finished the correction of the errors at the perspective and click in the cover-flow component. Now the perspective stays the same 150vw value (that is based on the screen width) and stays normal, with everything working. Oh man, that needed a lot of logic and out of box thinking finding another ways to check where the user clicked without using an normal click event listener (for those who lost the past devlog or didnt understood, i cannot use a normal eventListener in that because the clicks is detected in another element or in nothing, even with z-index or more in css, so the solution should be done entirely on javascript logic).
The first video is the new way, the second is how it was before all changes in it
i finished the workings on the section of the home page that i where doing before, now has a good responsiveness for pc and a decent one for mobile.
Now im working on the main area of the home page, the one where the user selects the desired genre for the music (second img). It may looks completely fine, but that same element already was a headache before and is here again. The given area is the cover-flow component, before i already fixed it (or so i thought), but it was looking bad (the 3d perspective where a bit strange) and would probably broken if i added new genres.
I were trying to figure out a way to listen to the clicks in the card without any problems, that seems easy at first glance, but the 3d perspective in the element make other elements eat the click from one another, make the clicks dont be listened and so many problems that i nearly decided to erase it and write from scratch. I already found a way to do it by using the mouse position, the center of the screen and the card width (the genre img) to transform it in an value that can be used to select the exact card without any dependencies on the doom selector. It basically uses just some values, put in some calcs and get the difference between the current card (genre) index and the clicked.
Im nearly finishing it, but i still need to figure out some values and more.
Im improving the responsiveness at the home page (before was the player page), but for some reason that idk the emotion selection div is having a strange behavior, i will update what it is after i fix it. Take a look: (the item in the center should be centered)
Hi again! Like said in the past devlog, im improving the responsiveness of the website, specifically in the player part. But it had some problems and where distorting when playing an video, now it resizes based on the screen size in a way that it stays ¨normal¨.
The first video is the new way, the second is the old way.
It still needs a lot of improvements, but it is going!
Hi again! Like i said in some devlog, the website dont have support for mobile, that was because it was designed to be at kiosk mode and work just in desktops. but i decided to change that.
First of all: the site where using a lot of absolute values of dimensions, so it where braking even in the desktops (it wasnt responsive at all). But i spent a while changing it, it is isnt ready and has some problems, but is better than before.
(The mobile is still strange, i did not started fixing it yet).
Credits:
https://css-tricks.com/snippets/css/fluid-typography/ - This website shows about a way to make the texts become responsive for the screen using some calcs, it is worth seeing.
The first video is how it was before, the second is how it is now
Context: There was an class called youtubeFrameControls, this class basically where designed as an structure to help using the youtube iframe API, but with the time this class where becoming basically to hold just an function (and in a very inefficient way), because the methods that it had before (like the one that runs when the iframe is loaded) had to have more and more specific logic in the codes that used it, so they where useless (because the codes that where using it where rewriting it).
What i did: I picked the only function that where being used and transformed it in an helpers (that can easily be customized). This function was the one that creates the player of the musics, and the function where called createPlayer. Also i removed the old class (youtubeFrameControls) and replaced it for this helper in every place that used it.
It now is way more simple than before and can me more customized.
I where placing some scripts in a class. These scripts are related with the player functions of the copa script, so i pick all of them and placed in the same class. I did it to follow best practices, but i confess that i still got some doubts about when to create an class and when the variable or method should be static or private (#property), i will search and learn more about because maybe i will have to refactor some parts of the code following these rules of best practices. That was all for now, see ya!
I added some checks in the player class at the startExplication function that checks if the src (the url for the audio) is valid or not by doing an fetch with the HEAD method and checking if the return is an valid audio before trying anything in this function. Also i solved this error in the same function:
Uncaught (in promise) AbortError: The play() request was interrupted because the media was removed from the document. https://goo.gl/LdLk22
This error was because the startExplication function where trying to play the audio before it was loaded, i solved it by making it play the audio just after it was load with the event listener canplaythrough.
There was another error at the playMusic function where the code where trying to play the youtube video before it was loaded, i solved it by making it wait until it was CUED (Where the video isnt playing, but is loaded and showed).
(The website was not created to be in mobile and dont has a lot of support, the video where recorded in my smartphone because i had to record the audio and the audio on my pc dont work. In the Future i Will add mobile suport, but right now im finishing the bugs and etc)
So basically there was an place where was designed to have the description about an music, but that was empty and where only finished today
It is petty simple, it just show an text about the music that is currently playing, also there is an audio that plays before the music starts playing, but this audios is played just one time before the music so if someone loses it or didnt listen well there was not a second chance to listen for that audio. Now there is this place that holds the same content, but in the format of an text that can be read whenever they want while the music is being played, that was what i added.
Also that text can be hidden, so it will not stay using half of the screen every time (in the screenshot it is active)
This audio / text is part of the main purpose of the website, they give some fun facts about the music that may be useful someday in some kind of quiz or essay.
Also the audio is played before the music and the music plays just after the audio finishes. That is to make whoever is listening listen to the entire audio before having what he (or she) wants, so they will not listen to the music and skip the audio.
So basically i where studing about cache, the main ideia was to implement it in the sistem, but then i realized something:
I realized it afther a while studing about it, but anyway lets focus on another thing.
Also i where studing with google for devs: https://developer.chrome.com/docs/workbox/caching-strategies-overview
The toast notification component is now being used at the player class, i did some tests and it is working very nice, hopefully the user will not see it very often (because that would be a problem, the user must not see it unless there is an error playing the music).
It is used to show more about what is going on for the user, so they will not become anxious if it something is working or not.
Each notification system has its own use cases, the others would be very painful for the user. Imagine every time a simple error (that is simple for me) like the music fail to play there was an error that interrupt the use of the app with an popup or alert, that would be painful, dont it?
That is why i used an toast notification, because it is temporary (disappears after some seconds) and dont stop the use of the website.
Also there is a feature that i implemented for the same reason a few devlogs ago that add a fallback in the music search, so it wont show a message at every single combination.
Lets calculate how many combinations we have: there is around 50 musics in the database, 22 genres and around 40 emotions, multiplying the genres and the music 880 combinations that the user can make. Now lets see how many musics we can get: each music have around 1.2 emotions and 1.2 genres, so we get 72 combinations that lead to an music. With that in mind, we can see that from 880 combinations, just 72 of them are useful combinations, so we get a 8.18% for getting a music, and 91,12% of not getting one. Consider that each failed attempt shows an error that stop the use flow of the website, but that was before the past devlog, now it tries again and again and only afther failing everything it shows an error, at that point it must really show an error.
Thats all, sorry for the long boring text and thanks everyone that read, see yall later
So i finished it, it is a component that u adds in the code that u wants to use. I added 2 icons, 1 for infos and another for warnings.
The element that holds it all is an dialog, the icons are svg, the text is a span and the element that shows the time left is an progress.
To update the time left i used an setInterval that runs at a 10ms delay and deduce 0.01 of the dialog value, so it will be smooth to see. Also there is an if inside that destroy the element and clear the interval when the value of the dialog reaches zero or less (In the past devlog i said about not using an if, but considering how low the cost for an if in that time is i decided to use it anyway).
The function that creates the toast receives some params that will let it be customized by whoever is calling it:
const icons = Object.freeze({
INFO: infoIcon(),
WARNING: warningIcon()
});
function createToast({ message, time = 5, styles, icon = icons.INFO })
// the `message` is the displayed message
// the `time` is the time until close
// the `styles` is custom css styles for the element, it uses the dictionary format {}
// the `icon` is the svg icon
I will apply it in some elements and post about. See you later!
So rn im creating what i said in the past devlog about a toast navigation. This isnt finished yet, im still figuring out an way to check the end of the timer, i found some ways to do it, like using an simple if inside the countdown. I didnt comment but i am using an setInterval to decrease the time and an <progress> tag to show the value
but that is a bad ideia, imagine doing 1 if every 50 ms? that dont cost a lot of processing power, but i still will search for other ways to do it just to check, if yall got any hints or ideas leave a comment.
Also i will improve the design, the design is petty poor.
Hi everyone, so i were fixing some bugs that i saw that may broke the app, i fixed all of them (for now), here they are:
/api/songs with params at the wrong format. Afther the past devlog the API started using the params genre_id and emotion_id, but the frontend where passing with the incorrect name (genre, emotion).player class, now if it fails it pass to the next music.I want to implement a simple toast notification system that will apear when something fails, like the playing of some music.
The youtube docs for the iframe where very helpful for this changes, check it out: https://developers.google.com/youtube/iframe_api_reference?hl=pt-br
So there was a certain part of the code responsible for the songs queue in the main route, that piece is a core function but where running a while true loop for no reason, here is the part:
async start() {
while (true) { // { emotion, genre, author, name, sourceId }
const musicData = await this.#musicQueue.get();
this.createPlayer(musicData['sourceId'], null);
this.#showMusicInfos(musicData['name'], musicData['author']);
this.#queueList.removeChild(this.#queueList.children[0]);
await this.#startExplication(`/storage/${musicData['explicationSource']}`);
this.player.playVideo();
await this.#musicFinished.when(true);
this.#musicFinished.set(false);
}
}
Basically the code were calling it at the start and running it forever, but that code where a nightmare to maintain / implement, i tried to implement a safe check here for over 2 hours, but wasnt possible.
I replaced it for a more efficient approach that do a loop in a different way, here it is:
play function (from the above topic).That is just it, no while or constant loops, no overhead, it works by basically connecting all the codes in a way that they work together to maintain (or stop) the loop (notice how i said loop, it uses a loop but isnt a while or for loop, it connects the end of one code and the start of another, like a chain.
I made it in the pull request #2, check it out: here
So at this devlog i were fixing some bugs in a specific ui / route called ¨copa¨, this is a special route added because a teacher asked our team to create them to use at some football games in our school. But since it was a hiddend route and mostly like a easter egg it hasnt been updated in a while and wasnt working anymore.
** That where all for that mode, but i didnt spent 5 hours just on it, i made more: **
conn = mysql.connector.connect(**configs)
cursor = conn.cursor(Dictionary=True)
But all the codes where using the same connection and cursor, so i decided to apply a connecton pool and make each database call get a connection and a new cursor.
Also i added some functions to abstrac the connection and query part:
def __get_connection(self):
conn = self.db_pool.get_connection()
conn.ping(reconnect=True, attempts=3, delay=1)
return conn
def __execute_query(self, query: str, params: list | None = None, dictionary=True, query_type: QueryTypes = QueryTypes.ALL):
conn = self.__get_connection()
try:
with conn.cursor(dictionary=dictionary) as cursor:
cursor.execute(query, (params) or ())
match query_type:
case QueryTypes.ALL:
return cursor.fetchall()
case QueryTypes.ONE:
return cursor.fetchone()
case QueryTypes.EXECUTE:
cursor.commit()
return cursor.lastrowid or cursor.rowcount
case _:
raise ValueError(f"Tipo de consulta não suportado: {query_type}")
If yall want to see it check here at my repo
That was also the first time that i used a Enum (on code) and branchs (on github, but i didnt used them properly)
There was also some other changes, check the repo GF-Silva/Ritualia
Now i will add some bug checks on a piece of code that handle the video display using an youtube iframe.
I spent a while (more than i expected) changing some strange values that control some settings of a component called cover-flow (this component create and control the images that are displayed in the home screen).
I spent more time figuring out what where each variable and lhe logic behind than acually writing.Before it had some hardcoded values that would probably broke if anything changes, i saw it and solved. I wasnt here for it, i was fixing another bug and fixed it before it broke.
I also used some basic math of circles like angle of an arc. That is all for today
I spent some time correcting errors and logic problems, here they are:
Music playback would freeze when the music queue ended: This problem would break the app until you restarted it, but it was very simple to solve. I had simply made it remove the first instance of music from the HTML twice, which caused it to try to remove an element that didn’t exist, thus freezing the app.
Removed an unnecessary loop: In the player section, there was a loop that iterated through all the elements (emotions) in a list to toggle the state of ONLY 1 ELEMENT. With the few elements it had (there were 3), this was minimal, but adding more could be detrimental to functionality. It only did this to toggle the state of the PREVIOUS element from active to inactive. I solved this simply by making it save the index of the last element and use that to access it. It took a while to work because javascript was treating 0 (the first indice / old indice when u start) as false in the if, but afther i figured out why it was simple to solve (if oldIndice != null)
I separated the API/WEB routes: Previously, the routes exposed by the backend (such as /songs) were in the same file. This wasn’t a problem before, but with the addition of new functions, it could become difficult to maintain and prone to various errors, as the routes weren’t separated (a name could be the same). Therefore, I separated them into: /api (backend API codes) and / (frontend web codes).
I put the genres in the database: Previously, the genres were in the frontend, and to add a new one, I would have to update both the backend and the frontend. To solve this, I simply added a route that retrieves the current genres (from the database) and uses the data (name / location) to load them into the frontend.
I added the emotions to the database: The emotions had the same problem; although both (they and the genres) were in the database, the frontend wasn’t based on that data, so I did the same thing I did with the genres.
I changed the name of where the music explanations were saved: I must have mentioned in a devlog that the folder inside storage was called /explication_source, and I also mentioned that the name was incorrect (because the audio source wasn’t there, nor would it be; the audio files themselves are there), so I changed it to /explication_audios
I saw a post about how to structure a README, how to make it clear and etc. Afther i realized how wrong the old README was (it was confusing, and also was months out of date).
So I chose some topics that would be interesting to include in and filled in a skeleton, spending some time learning what to do and what not to do.
I also didn’t fill in some fields because they aren’t ready yet (they now are stored in my memory to add later).
How it was before: https://github.com/GF-Silva/RitualIa/blob/9a2a7756c777a7042eca28309924e5a408bd561f/README.md
How it is now: https://github.com/GF-Silva/RitualIa/blob/2dea5f80266f06e8633af1aa3c9430065cde9231/README.md
There is a huge difference.
Also i did some bugs and noticed how bad my commits are
After a development pause, here are the various changes made.
Also, I never mentioned it, but this project was made by students focused on the school environment.
(This time I finally got around to writing the devlog myself):
Fixed the CoverFlow component: An error went unnoticed in the creation of the component, this made the size and spacing of the images look strange, it was fixed to a certain extent.
I implemented a new playback policy: The text about it got so long that I decided to open an extra topic.
Now it search for the requested emotion + genre that the user choose, If It fails It search Just for the genre, if It fails again it search for anything.
Now it falls into a fallback:
This policy change was motivated by having to find a song to show in a presentation and failing. I reflected that if it was annoying for me, it would be for the end user (students) as well.
But why would saving the songs in the cloud be a problem?
Nothing comes for free, the server we were using to host the music had a monthly access limit, which was a silent problem that, thankfully, was noticed before it happened.
My mistake, I didn’t even think about the possibility of saving locally and went straight to saving in the cloud, it must have been due to haste and inattention (always plan well what you are going to do before you do it, weigh the risks and benefits).
Now, how it works
/storage folder.Yes, but at some point the path might change (e.g., explication_source/youtube/audio_legal.extension).
RitualIa in Evolution: Refactoring, Optimization, and New Features 🎶
Hey everyone! I’m back with a cool update on what’s been happening here at RitualIa.
After that commit where we transformed some scripts into helpers, things have evolved quite a bit. We’ve been doing a heavy refactoring of the project, focusing on organization, performance, and better code architecture.
What’s changed:
Structure & Organization: I removed legacy folders that weren’t being used, did a mega merge bringing everything from /frontend (the folder that where holding ALL the frontend logics) to the project root (with that the frontend and backend are in the same folder), and switched from FastAPI to Flask on the backend. Why the change of FastAPI to Flask:
Because my supervisor or mentor (something like this) said and said again to, because there was other guys in the project (still is, but im the main developer, the others stopped doing anything like mounths Ago, and even while they where doing something i still was the main dev), these other guys where total starters and could not hold the learning curve of FastAPI (even with the fact that was Just me that where using It, because it was at the backend and i was the only developing at back).
Code Quality: We made several methods private in the PlayerControls class, making the API cleaner and more secure. We also fixed the “enclosing class errors” that appeared. These small fixes make a huge difference in code reliability.
UI/UX Improvements: We created a new CoverFlow component to replace GenreCylinder on the homepage – it’s much smoother and prettier now. We added support for async onClick, grab + touch in CoverFlow, and adjusted visual positioning to keep everything aligned. Oh, and we removed that unnecessary playerText that was cluttering the interface.
New Features: A really cool feature that was added was the checking for duplicate songs in the queue. Nothing worse than accidentally playing the same song twice, right? Now that doesn’t happen anymore.
Maintenance & Updates: We updated the fetches to call the new routes, moved the favicon to assets (because everything has its place), and focused on the details.
What’s coming next:
We are in a consolidation phase, laying a solid foundation for the upcoming features. The focus now is on ensuring that each component is doing exactly what it needs to do, nothing more, nothing less.
Thanks for following along!
I’m transforming some duplicate code into helpers so they can be more easily used in new code.
Introducing: The ‘Ritualia’ project is a project developed by me and some colleagues with the help of the school. In it, we have done and continue to do research and assembly with the aim of impacting the daily lives of students in our school and (in the future) other schools. It is an open-source project with an article soon to be published detailing the foundations used, etc. The readme is currently outdated because I am redoing part of the current architecture, but I will update it later to include information on how to assemble and create your own version. The project is divided into hardware and software. I, along with other members, am responsible for the software (which is usable on most computers), and the hardware is relatively simple (it only depends on a display + sound + a controller with an OS + the preparations for installation).