Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Playlists - take backup before running every fresh library build #149

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</parent>
<groupId>com.gmt</groupId>
<artifactId>g-player</artifactId>
<version>2.4.8</version>
<version>2.4.9</version>
<name>G-Player-SB</name>
<description>G-Player-SB</description>
<properties>
Expand Down Expand Up @@ -82,6 +82,13 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20240303</version>
</dependency>


</dependencies>
<build>
Expand Down
15 changes: 13 additions & 2 deletions src/g-player-react/src/Components/CommnPopup.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,19 @@ export const CommonPopup = () => {
<div className="popup-footer">
<div className='buttons'>
<button type="button" className="popup-btn-secondary" onClick={closePopup}>Cancel</button>
<button type="button" className={`popup-btn-primary ${commonPopupObj.className} ${commonPopupObj.primaryClassName}`}
onClick={commonPopupObj.dispatchPayload ? ()=>dispatch(commonPopupObj.primaryBtnFun(commonPopupObj.payload)) : ()=>commonPopupObj.primaryBtnFun(commonPopupObj.args)}
<button type="button"
className={`popup-btn-primary ${commonPopupObj.className} ${commonPopupObj.primaryClassName}`}
onClick={
commonPopupObj.dispatchPayload ?
()=>dispatch(commonPopupObj.primaryBtnFun(commonPopupObj.payload))
:
()=>commonPopupObj.primaryBtnFun(
typeof commonPopupObj.args === "function" ?
commonPopupObj.args()
:
commonPopupObj.args
)
}
id={POPUP_PRIMARY_BTN}
>
{commonPopupObj.primaryBtnLabel?commonPopupObj.primaryBtnLabel:"Go"}
Expand Down
2 changes: 1 addition & 1 deletion src/g-player-react/src/Components/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { fetchCurrentSontAndStatus, playASongSucc, setIsShuffle, setMediaVolumeS
import { getCookieDetails, getCookieValue, setCookies } from "./utilities/util";
import { ALBUM, ARTIST, GENRE, LANGUAGE, MAIN_CONTAINER, PLAYLIST, RECENT_PLAYS, TRACK_LIST } from "./redux/GPActionTypes";
import { Route, Routes } from "react-router-dom";
import { Library } from "./library/Library";
import { Library } from "./library/LibraryV2";
import { Search } from "./search/Search";
import { RecentPlays } from "./history/RecentPlays";
import { Playlist } from "./playlist/Playlist";
Expand Down
73 changes: 73 additions & 0 deletions src/g-player-react/src/Components/library/ArtistImageDownload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { ARTIST_IMG_DOWNLOAD_STATUS, COMPLETED, COMPONENT, RUNNING } from "../redux/GPActionTypes";
import { initiArtistImageDownload, setCommonPopupObj } from "../redux/library/LibraryActions";
import loading_icon from '../images/Loading.gif';

export const ArtistImageDownload = () => {
const dispatch = useDispatch();
const artistImageDownloadSummary = useSelector(state => state.library.artistImageDownloadSummary);

const [artistIImgDownloadStat, setArtistIImgDownloadStat] = useState({});


useEffect(()=>{
if(artistImageDownloadSummary && artistImageDownloadSummary.length > 0){
const status = artistImageDownloadSummary.find(elem => {return elem.name === ARTIST_IMG_DOWNLOAD_STATUS});
setArtistIImgDownloadStat(status);
}
},[artistImageDownloadSummary]);



const initiateArtistImageDownload = () => {
const artistImgDownloadOtnSlct = document.getElementById("ARTIST_IMAGE_DOWNLOAD_OPTIONS_SELECT");
if(!artistImgDownloadOtnSlct){
return false;
}
if(window.confirm("Initiate Download ?")===true){
const tempArtistIImgDownloadStat = {
"name": "ARTIST_IMG_DOWNLOAD_STATUS",
"value": "RUNNING",
"type": "ARTIST_IMG_DOWNLOAD_STATUS"
}
setArtistIImgDownloadStat(tempArtistIImgDownloadStat);
dispatch(initiArtistImageDownload(artistImgDownloadOtnSlct.value));
dispatch(setCommonPopupObj({showPopup: false}));
}
}
const getArtistImgPopupObj = () => ({
showPopup: true,
title: "Download Artist Images",
contentType: COMPONENT,
component: ()=>{
return(
<div className="artist-image-download-popup-content">
<p style={{marginBottom:10}}>Select download option</p>
<select className="gp-select" style={{width:'60%'}} id="ARTIST_IMAGE_DOWNLOAD_OPTIONS_SELECT">
<option value="IGNORE_EXISTING_AND_TRIED_AND_FAILED">Ignore existing and failed in previous download</option>
<option value="DOWNLOAD_ALL">Download all</option>
<option value="DOWNLOAD_ALL_AND_OVERRIDE">Download all - Override existing</option>
<option value="DOWNLOAD_LATEST" disabled>Download latest</option>
</select>
</div>
)
},
primaryBtnFun: initiateArtistImageDownload,
primaryBtnLabel: "Download"
})
return(
<div className="library-artist-download">
<label>Download Artist Images</label>
<p style={{marginTop:10}}>Download Status: &nbsp;
<>
{artistIImgDownloadStat && artistIImgDownloadStat.value === RUNNING && <>{RUNNING} <img src={loading_icon} style={{height:12}} /></>}
{artistIImgDownloadStat && artistIImgDownloadStat.value === COMPLETED && COMPLETED}
</>
</p>
<div className="btn-container">
<a className="library-btn" onClick={()=>dispatch(setCommonPopupObj(getArtistImgPopupObj()))}>Initiate Download</a>
</div>
</div>
);
}
104 changes: 104 additions & 0 deletions src/g-player-react/src/Components/library/BuildLibrary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { useEffect, useState } from "react";
import { ARTIST_IMG_DOWNLOAD_STATUS, BUILD_STATUS, COMPLETED, COMPONENT, CURRENT_PAGE, GP_LIBRARY_DESCRIPTION, GP_LIBRARY_DESC_TEXT_1, INIT, INITIATED, LIBRARY, LIBRARY_BUILD, LIBRARY_LABEL, MUSIC_PATH, RUNNING } from "../redux/GPActionTypes";
import { fetchBuildStatusSucc, initLibraryBuild, setCommonPopupObj } from "../redux/library/LibraryActions";
import { useDispatch, useSelector } from "react-redux";
import { setCookies } from "../utilities/util";
import loading_icon from '../images/Loading.gif';
import { BuildLibraryPopup } from "./BuildLibraryPopup";


export const BuildLibrary = () => {
const dispatch = useDispatch();

const buildStatusList = useSelector(state => state.library.buildStatus);

const [isBuildRunning, setIsBuildRunning] = useState(false);
const [isBuildInit, setIsBuildInit] = useState(false);
const [buildStatusL, setBuildStatusL] = useState(null);

useEffect(()=>{
if(buildStatusList.length > 0){
const buildStatus = [...buildStatusList].find(bs=>bs.name===BUILD_STATUS);
if(buildStatus)setIsBuildRunning(buildStatus.value === RUNNING ? true : false);

let tempBuildStatusL = {};
if(buildStatusList.length>0){
buildStatusList.forEach(element => {
tempBuildStatusL[element.name]=element.value;
});
setBuildStatusL(tempBuildStatusL);
}
}
},[buildStatusList])

const onInitLibraryBuild = (isTakePlBkp) => {

if(window.confirm("Build library ?")===true){
dispatch(initLibraryBuild(isTakePlBkp));
const tempBuildStatus = [...buildStatusList].filter(bs=>bs.name!==BUILD_STATUS);
tempBuildStatus.push({
"name": BUILD_STATUS,
"value": RUNNING,
"type": BUILD_STATUS
});
console.log("tempBuildStatus: ",tempBuildStatus)
dispatch(fetchBuildStatusSucc(tempBuildStatus));
setCookies(LIBRARY_BUILD, INITIATED);
}
}
const showBuildLibPopup = () => {
const commonPopupObj = {
showPopup: true,
title: "Build Library",
component: BuildLibraryPopup,
contentType: COMPONENT,
primaryBtnFun: onInitLibraryBuild,
primaryBtnLabel:"Build",
args : () => {
return document.getElementById("build_playlist_backup_chkbox").checked;
}

}
const buildStatus = [...buildStatusList].find(bs=>bs.name===BUILD_STATUS);
buildStatus.value=INIT;
const tempBuildStatus = [...buildStatusList].filter(bs=>bs.name!==BUILD_STATUS);
tempBuildStatus.push(buildStatus);
dispatch(fetchBuildStatusSucc(tempBuildStatus));
dispatch(setCommonPopupObj(commonPopupObj));
}
return(
<div className="library-build">
<h4>Build Library</h4>
<div className="content">
<p>{GP_LIBRARY_DESCRIPTION}</p>
<p>{GP_LIBRARY_DESC_TEXT_1}</p>
</div>
<div className="status">
{!isBuildRunning && buildStatusL &&
<div className="completed">
<label>Summary of current build</label>
<label><span>Total tracks</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;{buildStatusL.TOTAL_TRACKS}</span></label>
<label><span>Total albums</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;{buildStatusL.ALBUM_COUNT}</span></label>
<label><span>Artists found</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;{buildStatusL.ARTIST_COUNT}</span></label>
<label><span>Album Artists found</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;{buildStatusL.ALBUM_ARTIST_COUNT}</span></label>
<label><span>Time took to finish</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;{Math.floor(buildStatusL.FILES_READ_TIME/1000)} Secs</span></label>
</div>
}
{isBuildRunning && buildStatusL &&
<div className="running">
<label>Status</label>
{!isBuildInit && <>
<label><span>Rading files:</span><span>{buildStatusL.FILES_TO_READ} remaining.</span></label>
<label><span>Build status:</span><span>{buildStatusL.BUILD_STATUS}&nbsp;<img src={loading_icon} style={{height:12}} /></span></label>
<label><span style={{width:'100%'}}>{buildStatusL.BUILD_STATUS_STEP}</span></label>
</>}
{isBuildInit && <label><span>Build Initiated</span></label>}
</div>
}
</div>
<div className="btn-container">
<a className={!isBuildRunning?"library-btn":"library-btn disabled-click"} onClick={showBuildLibPopup}>Build Library</a>
</div>
</div>
);
}
48 changes: 48 additions & 0 deletions src/g-player-react/src/Components/library/BuildLibraryPopup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { useEffect, useState } from "react";
import { ARTIST_IMG_DOWNLOAD_STATUS, BUILD_STATUS, COMPLETED, COMPONENT, CURRENT_PAGE, GP_LIBRARY_DESCRIPTION, GP_LIBRARY_DESC_TEXT_1, INIT, INITIATED, LIBRARY, LIBRARY_BUILD, LIBRARY_LABEL, MUSIC_PATH, RUNNING } from "../redux/GPActionTypes";
import { initLibraryBuild, setCommonPopupObj } from "../redux/library/LibraryActions";
import { useDispatch, useSelector } from "react-redux";
import { setCookies } from "../utilities/util";
import loading_icon from '../images/Loading.gif';
import { Spinner } from "../utilities/Spinner";


export const BuildLibraryPopup = () => {
const dispatch = useDispatch();

const buildStatusList = useSelector(state => state.library.buildStatus);
const [isBuildRunning, setIsBuildRunning] = useState(false);
const [isBuildCompleted, setIsBuildCompleted] = useState(false);
const [isBuildInit, setIsBuildInit] = useState(false);

console.log("isBuildRunning:", isBuildRunning)

useEffect(()=>{
if(buildStatusList.length > 0){
const buildStatus = [...buildStatusList].find(bs=>bs.name===BUILD_STATUS);
if(buildStatus){
setIsBuildRunning(buildStatus.value === RUNNING ? true : false);
setIsBuildCompleted(buildStatus.value === COMPLETED ? true : false);
setIsBuildInit(buildStatus.value === INIT ? true : false);
}
}
console.log("buildStatusList: ",buildStatusList)
},[buildStatusList])

useEffect(()=>{
if(isBuildCompleted)dispatch(setCommonPopupObj({
showPopup: false
}));
},[isBuildCompleted])
return (
<>
{!isBuildRunning &&
<div className="flexbox-align-center" style={{columnGap:10}}>
<span>Take backup of playlists before build ?</span>
<input type="checkbox" id="build_playlist_backup_chkbox" className="custom-checkbox" style={{border:'1px solid', borderRadius:3}} />
</div>
}
{(isBuildRunning) && <div className="flex-align-center-100"><Spinner spinnerInp={{classSize:'sm', text:"Builing"}} /></div>}
</>
);
}
35 changes: 35 additions & 0 deletions src/g-player-react/src/Components/library/LibraryV2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useEffect, useState } from "react";

import { useDispatch } from "react-redux";
import { fetchBuildStatus, fetchMessagesByType, fetchMusicPath} from "../redux/library/LibraryActions";
import { ARTIST_IMG_DOWNLOAD_STATUS,bCURRENT_PAGE, CURRENT_PAGE, LIBRARY, LIBRARY_LABEL} from "../redux/GPActionTypes";

import { Header } from "../header/Header";
import { setCookies } from "../utilities/util";
import { ArtistImageDownload } from "./ArtistImageDownload";
import { MusicLibraryPath } from "./MusicLibraryPath";
import { BuildLibrary } from "./BuildLibrary";

export const Library = () => {

const dispatch = useDispatch();

useEffect(()=>{
dispatch(fetchMusicPath());
dispatch(fetchBuildStatus());
setCookies(CURRENT_PAGE, JSON.stringify({type:LIBRARY}));
dispatch(fetchMessagesByType(ARTIST_IMG_DOWNLOAD_STATUS));
},[])


return(
<div className="library-v2">
<Header headerLbl={LIBRARY_LABEL} />
<div className="body">
<BuildLibrary />
<MusicLibraryPath />
<ArtistImageDownload />
</div>
</div>
);
}
54 changes: 54 additions & 0 deletions src/g-player-react/src/Components/library/MusicLibraryPath.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useEffect } from "react";
import { MUSIC_PATH } from "../redux/GPActionTypes";
import { useDispatch, useSelector } from "react-redux";
import { deleteMusicPath, saveMusicPath } from "../redux/library/LibraryActions";
import {RiDeleteBinLine} from 'react-icons/ri';
import { LIBRARY_SAVE_MUSIC_PATH_SUCCESS } from "../redux/library/LibraryActionTypes";

export const MusicLibraryPath = () => {
const dispatch = useDispatch();

const musicPaths = useSelector(state => state.library.musicPaths);
const libraryPhase = useSelector(state => state.library.phase);

useEffect(()=>{
if(libraryPhase===LIBRARY_SAVE_MUSIC_PATH_SUCCESS){
document.getElementById('music_path').value = "";
}
},[libraryPhase]);

const onSaveMusicPath = () => {
const mPath = document.getElementById('music_path').value;
if(mPath===""){
alert("Path cannot be empty");
return;
}
const musicPath = {
name : MUSIC_PATH,
type: MUSIC_PATH,
value: mPath
}
try {
dispatch(saveMusicPath(musicPath));
} catch (error) {
console.log(error)
}
}
return(
<div className="library-list">
<h4>Library List</h4>
<div className="content">
<p>Add all the music folders' full path.</p>
<div className="input-container">
<input id="music_path" placeholder="Paste music path" />
<a className="library-btn" onClick={onSaveMusicPath}>Add</a>
</div>
</div>
<div className="existing-lib-paths">
{musicPaths && musicPaths.map((musicPath, index)=>
<label key={index}>{musicPath.value}<RiDeleteBinLine onClick={()=>dispatch(deleteMusicPath(musicPath))} /></label>
)}
</div>
</div>
);
}
7 changes: 6 additions & 1 deletion src/g-player-react/src/Components/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1970,7 +1970,7 @@ a.disabled-click{
height: 74%;
}

.library {
.library, .library-v2 {
width: 78vw;
.header{
margin-left: 10px;
Expand Down Expand Up @@ -3185,6 +3185,11 @@ a.disabled-click{
align-items: center;
justify-content: center;
}

.flexbox-align-center{
display: flex;
align-items: center;
}
//common classes - end
//GLobal components styling - end

Expand Down
Loading