Try this
This commit is contained in:
parent
9d63882e69
commit
7ef8650457
|
|
@ -2,3 +2,4 @@ build
|
|||
output
|
||||
node_modules
|
||||
public
|
||||
jam_track_tracks_for_jam_ui*
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import React from "react";
|
|||
import ReactDOM from "react-dom";
|
||||
import Main from "../src/Main.js"
|
||||
import TemplatePage from "../src/components/jamtracks/JKJamTracksLandingTemplatePage.js"
|
||||
import ArtistTemplatePage from "../src/components/jamtracks/JKJamTracksArtistLandingTemplatePage.js"
|
||||
import '../src/helpers/initFA';
|
||||
import '../src/i18n/config';
|
||||
|
||||
|
|
@ -12,14 +13,7 @@ const rootElement = document.getElementById("root");
|
|||
|
||||
// Ensure props are passed correctly (or fetch from the server)
|
||||
|
||||
const props = window.jamtrack_data ? window.jamtrack_data : {
|
||||
id: rootElement.dataset.id,
|
||||
plan_code: rootElement.dataset.plan_code,
|
||||
slug: rootElement.dataset.slug,
|
||||
artist: rootElement.dataset.artist,
|
||||
song: rootElement.dataset.song,
|
||||
location: window.location.pathname,
|
||||
};
|
||||
const props = window.jamtrack_data;
|
||||
|
||||
console.log('init', props, rootElement);
|
||||
|
||||
|
|
@ -28,7 +22,7 @@ console.log('init', props, rootElement);
|
|||
|
||||
ReactDOM.render(
|
||||
<Main>
|
||||
<TemplatePage {...props} />
|
||||
{props.song ? <TemplatePage {...props} /> : <ArtistTemplatePage {...props} /> }
|
||||
</Main>, rootElement
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,11 +9,16 @@ fi
|
|||
|
||||
echo "Saving to $SAVE_TO"
|
||||
|
||||
psql jam -c "COPY( select id, original_artist, name , original_artist_slug, name_slug, plan_code, slug, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug || '/' || name_slug) as \"URL\", (select name from jam_track_licensors l where l.id = licensor_id) as \"Licensor\", vendor_id as \"Vendor ID\" FROM jam_tracks) TO '$SAVE_TO/jam_tracks_for_jam_ui.$USER.csv' with CSV HEADER;"
|
||||
psql jam -c "COPY( select id, original_artist, name , original_artist_slug, name_slug, plan_code, slug, allow_free, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug || '/' || name_slug) as \"URL\", (select name from jam_track_licensors l where l.id = licensor_id) as \"Licensor\", vendor_id as \"Vendor ID\" FROM jam_tracks) TO '$SAVE_TO/jam_tracks_for_jam_ui.$USER.csv' with CSV HEADER;"
|
||||
|
||||
//https://jamkazam-public.s3.amazonaws.com
|
||||
|
||||
# dump all artists
|
||||
psql jam -c "COPY( select original_artist, original_artist_slug, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug ) as \"URL\" FROM jam_tracks group by original_artist, original_artist_slug) TO '$SAVE_TO/jam_tracks_for_jam_ui_artists.$USER.csv' with CSV HEADER;"
|
||||
|
||||
psql jam -c "COPY( select id, part, instrument_id, (select description from instruments where id = instrument_id) as instrument_description, track_type, position, preview_mp3_url, preview_url as preview_ogg_url, preview_acc_url from jam_track_tracks) TO '$SAVE_TO/jam_track_tracks_for_jam_ui.$USER.csv' with CSV HEADER;"
|
||||
|
||||
echo "Moving personal files to $SAVE_TO"
|
||||
sudo mv $SAVE_TO/jam_tracks_for_jam_ui.$USER.csv .
|
||||
sudo mv $SAVE_TO/jam_tracks_for_jam_ui_artists.$USER.csv .
|
||||
sudo mv $SAVE_TO/jam_track_tracks_for_jam_ui.$USER.csv .
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Ensure the correct number of arguments
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "Usage: $0 <save_to_path> <server_env>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SAVE_TO="$1"
|
||||
server_env="$2"
|
||||
|
||||
# Validate server_env
|
||||
if [ "$server_env" != "staging" ] && [ "$server_env" != "production" ]; then
|
||||
echo "Error: server_env must be either 'staging' or 'production'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine SSH target
|
||||
if [ "$server_env" == "staging" ]; then
|
||||
SSH_TARGET="jam@int.jamkazam.com"
|
||||
else
|
||||
SSH_TARGET="jam@db.jamkazam.com"
|
||||
fi
|
||||
|
||||
echo "Saving to $SAVE_TO on $server_env"
|
||||
|
||||
# Run psql commands remotely
|
||||
ssh $SSH_TARGET "psql jam -c \"COPY( select id, original_artist, name, original_artist_slug, name_slug, plan_code, slug, allow_free, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug || '/' || name_slug) as \"URL\", (select name from jam_track_licensors l where l.id = licensor_id) as \"Licensor\" FROM jam_tracks order by id::int) TO '$SAVE_TO/jam_tracks_for_jam_ui.$server_env.csv' with CSV HEADER;\""
|
||||
|
||||
ssh $SSH_TARGET "psql jam -c \"COPY( select original_artist, original_artist_slug, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug ) as \"URL\" FROM jam_tracks group by original_artist, original_artist_slug order by original_artist) TO '$SAVE_TO/jam_tracks_for_jam_ui_artists.$server_env.csv' with CSV HEADER;\""
|
||||
|
||||
ssh $SSH_TARGET "psql jam -c \"COPY( select id, part, instrument_id, (select description from instruments where id = instrument_id) as instrument_description, track_type, position, preview_mp3_url, preview_url as preview_ogg_url, preview_aac_url from jam_track_tracks order by jam_track_id::int) TO '$SAVE_TO/jam_track_tracks_for_jam_ui.$server_env.csv' with CSV HEADER;\""
|
||||
|
||||
# Move files locally from the remote server
|
||||
scp $SSH_TARGET:"$SAVE_TO/jam_tracks_for_jam_ui.$server_env.csv" jamtracks-for-env
|
||||
scp $SSH_TARGET:"$SAVE_TO/jam_tracks_for_jam_ui_artists.$server_env.csv" jamtracks-for-env
|
||||
scp $SSH_TARGET:"$SAVE_TO/jam_track_tracks_for_jam_ui.$server_env.csv" jamtracks-for-env
|
||||
|
||||
echo "Files moved successfully to local machine"
|
||||
|
|
@ -5,9 +5,41 @@ const React = require("react");
|
|||
const dotenv = require("dotenv");
|
||||
const ReactDOMServer = require("react-dom/server");
|
||||
const TemplatePageModule = require("./build/components/jamtracks/JKJamTracksLandingTemplatePage");
|
||||
const ArtistTemplatePageModule = require("./build/components/jamtracks/JKJamTracksArtistLandingTemplatePage");
|
||||
|
||||
var csvFilePath = `jam_tracks_for_jam_ui.${process.env.USER}.csv`
|
||||
var csvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui.${process.env.USER}.csv`
|
||||
var artistCsvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui_artists.${process.env.USER}.csv`
|
||||
|
||||
/**
|
||||
* Loads a CSV file into an array of objects.
|
||||
* @param {string} csvPath - The path to the CSV file.
|
||||
* @returns {Promise<Array<Object>>} - A promise that resolves with the parsed CSV data.
|
||||
*/
|
||||
const load_csv = (csvPath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const results = [];
|
||||
fs.createReadStream(csvPath)
|
||||
.pipe(csv())
|
||||
.on('data', (data) => results.push(data))
|
||||
.on('end', () => resolve(results))
|
||||
.on('error', (error) => reject(error));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds all songs for a given artist based on the original_artist_slug
|
||||
* and sorts them alphabetically by the `slug` field.
|
||||
* @param {string} artistSlug - The original_artist_slug to match.
|
||||
* @param {Array<Object>} songsCsv - The songs CSV data.
|
||||
* @returns {Array<Object>} - A sorted array of matching song objects.
|
||||
*/
|
||||
const collect_songs_for_artist = (artistSlug, songsCsv) => {
|
||||
return songsCsv
|
||||
.filter((song) => song.original_artist_slug === artistSlug)
|
||||
.sort((a, b) => a.slug.localeCompare(b.slug)); // Sort alphabetically by slug
|
||||
};
|
||||
|
||||
|
||||
const init = () => {
|
||||
const node_env = process.env.NODE_ENV || 'development';
|
||||
const environment = process.env.ENVIRONMENT || 'development';
|
||||
|
|
@ -15,10 +47,12 @@ const init = () => {
|
|||
console.log(dotenv.config({ path: `../.env.${environment}` }));
|
||||
|
||||
if (environment === "production" || environment === "staging") {
|
||||
csvFilePath = `jam_tracks_for_jam_ui.${environment}.csv`;
|
||||
csvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui.${environment}.csv`;
|
||||
artistCsvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui_artists.${environment}.csv`;
|
||||
}
|
||||
|
||||
console.log("using csv file", csvFilePath);
|
||||
console.log("Song csv file", csvFilePath);
|
||||
console.log("Artist csv file", artistCsvFilePath);
|
||||
|
||||
if (!process.env.PUBLIC_URL) {
|
||||
console.log("setting public url", process.env.REACT_APP_BASE_URL);
|
||||
|
|
@ -31,7 +65,7 @@ const init = () => {
|
|||
console.log("init done successfully")
|
||||
}
|
||||
|
||||
const generatePages = async (render) => {
|
||||
const generateSongPages = async (render) => {
|
||||
const rows = [];
|
||||
|
||||
const OUTPUT_DIR = path.join(__dirname, "..", "public", "backing-tracks");
|
||||
|
|
@ -53,7 +87,7 @@ const generatePages = async (render) => {
|
|||
|
||||
for (const row of rows) {
|
||||
// id, original_artist, name, original_artist_slug, name_slug, plan_code, slug, URL, licensor, vendor_id
|
||||
const { id, original_artist, name, original_artist_slug, name_slug, plan_code, slug } = row;
|
||||
const { id, original_artist, name, original_artist_slug, name_slug, plan_code, slug, allow_free } = row;
|
||||
const artist = original_artist;
|
||||
const song = name;
|
||||
const location = `/backing-tracks/${original_artist_slug}/${name_slug}`;
|
||||
|
|
@ -132,7 +166,6 @@ const generatePages = async (render) => {
|
|||
fs.mkdirSync(ARTIST_DIR, { recursive: false });
|
||||
}
|
||||
|
||||
console.log("process.env.NODE_ENV=", process.env.NODE_ENV);
|
||||
const finalOutputPath = process.env.NODE_ENV === "development" ? `${name_slug}.html` : name_slug;
|
||||
const outputFilePath = path.join(ARTIST_DIR, finalOutputPath);
|
||||
fs.writeFileSync(outputFilePath, fullHtml);
|
||||
|
|
@ -143,10 +176,112 @@ const generatePages = async (render) => {
|
|||
});
|
||||
};
|
||||
|
||||
const generateArtistPages = async (render) => {
|
||||
const rows = [];
|
||||
|
||||
const OUTPUT_DIR = path.join(__dirname, "..", "public", "backing-tracks");
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
console.log("generatPages starting")
|
||||
|
||||
|
||||
const TemplatePage = TemplatePageModule.default;
|
||||
|
||||
const songs_csv = await load_csv(csvFilePath);
|
||||
|
||||
fs.createReadStream(artistCsvFilePath)
|
||||
.pipe(csv())
|
||||
.on("data", (row) => rows.push(row))
|
||||
.on("end", async () => {
|
||||
console.log(`Processing ${rows.length} rows...`);
|
||||
|
||||
for (const row of rows) {
|
||||
const { original_artist, original_artist_slug, url } = row;
|
||||
const artist = original_artist;
|
||||
|
||||
const matchingSongs = collect_songs_for_artist(original_artist_slug, songs_csv);
|
||||
console.log(`Found ${matchingSongs.length} songs for ${artist}`);
|
||||
|
||||
const location = `/backing-tracks/${original_artist_slug}`;
|
||||
const fullPath = process.env.REACT_APP_BASE_URL + location;
|
||||
const logoPath = process.env.REACT_APP_BASE_URL + "/favicon.svg";
|
||||
|
||||
console.log(`Generating ${artist}`);
|
||||
|
||||
const songs = matchingSongs.map((song) => {
|
||||
return {
|
||||
name: song.name,
|
||||
plan_code: song.plan_code,
|
||||
url: process.env.REACT_APP_BASE_URL + "/backing-tracks/" + song.original_artist_slug + "/" + song.name_slug
|
||||
}
|
||||
});
|
||||
const html = render
|
||||
? ReactDOMServer.renderToStaticMarkup(
|
||||
React.createElement(ArtistTemplatePage, { artist, original_artist_slug, location })
|
||||
)
|
||||
: "";
|
||||
const fullHtml = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="shortcut icon" href="/favicon.svg">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>${artist} - Free Backing Track</title>
|
||||
<link rel="stylesheet" href="${process.env.REACT_APP_BASE_URL}/css/theme.css">
|
||||
<meta name="description" content="Get a free ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
|
||||
<meta name="keywords" content="Backing Track, ${artist}, Instrumental">
|
||||
<meta name="author" content="JamKazam">
|
||||
|
||||
<!-- Open Graph (Facebook, LinkedIn, etc.) -->
|
||||
<meta property="og:title" content="${artist} | Free Backing Track">
|
||||
<meta property="og:description" content="Get a free ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
|
||||
<meta property="og:image" content="${logoPath}">
|
||||
<meta property="og:url" content="${fullPath}">
|
||||
<meta property="og:type" content="music.song">
|
||||
|
||||
<!-- Twitter Cards -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="${artist} | Free Backing Track">
|
||||
<meta name="twitter:description" content="Get a free ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
|
||||
<meta name="twitter:image" content="${logoPath}">
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href="${fullPath}" />
|
||||
|
||||
<script>
|
||||
window.jamtrack_data = {
|
||||
artist: "${artist}",
|
||||
original_artist_slug: "${original_artist_slug}",
|
||||
location: "${location}",
|
||||
songs: ${JSON.stringify(songs)}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${html}</div>
|
||||
<script src="/js/client-hydrate.bundle.js"></script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const finalOutputPath = process.env.NODE_ENV === "development" ? `${original_artist_slug}.html` : original_artist_slug;
|
||||
const outputFilePath = path.join(OUTPUT_DIR, finalOutputPath);
|
||||
fs.writeFileSync(outputFilePath, fullHtml);
|
||||
console.log(`Generated: ${outputFilePath}`);
|
||||
}
|
||||
|
||||
console.log("All pages generated!");
|
||||
});
|
||||
};
|
||||
|
||||
let render = false;
|
||||
if (process.argv.length > 2) {
|
||||
render = process.argv[2] === "true" || process.argv[2] === "yes" || process.argv[2] === "1";
|
||||
}
|
||||
|
||||
init()
|
||||
generatePages(render);
|
||||
generateSongPages(render);
|
||||
|
||||
generateArtistPages(render);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -14,4 +14,8 @@
|
|||
.swiper-card {
|
||||
box-shadow: none !important;
|
||||
border: solid 1px #eee;
|
||||
}
|
||||
|
||||
.jk-blue-color {
|
||||
color: rgb(64,124,222);
|
||||
}
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
.jamtrack-landing-body.artist-landing-page {
|
||||
.preview-region.card {
|
||||
max-height:25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.content-row.landing-page {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
|
@ -69,14 +75,26 @@
|
|||
|
||||
.top-region-container {
|
||||
display: grid;
|
||||
grid-template-columns: 60% 40%;
|
||||
grid-template-columns: 50% calc(50% - 3rem);
|
||||
gap: 3rem; /* Adds spacing between them */
|
||||
}
|
||||
|
||||
|
||||
.jamtrack-listing-item {
|
||||
margin-bottom: 0rem;
|
||||
}
|
||||
|
||||
.jamtrack-listing-container {
|
||||
margin: 2rem 0 2.5rem 0;
|
||||
}
|
||||
|
||||
.preview-region {
|
||||
|
||||
.spinner-border {
|
||||
float: right;
|
||||
margin-top: -25px;
|
||||
}
|
||||
|
||||
/* Make it respect the height of the parent */
|
||||
max-height: 100%; /* Ensures it doesn't exceed parent height */
|
||||
overflow: auto; /* Enables scrolling if content overflows */
|
||||
|
|
|
|||
|
|
@ -67,6 +67,13 @@ const JKJamTrackTrack = ({ track, duration = null }) => {
|
|||
trackSound.pause();
|
||||
setIsPlaying(false);
|
||||
}
|
||||
|
||||
if (trackSound) {
|
||||
if (isPlaying) {
|
||||
trackSound.pause();
|
||||
}
|
||||
}
|
||||
|
||||
}, [currentPlayTrackId]);
|
||||
|
||||
const togglePlay = () => {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,19 @@
|
|||
import React from 'react'
|
||||
import { useParams, Link } from 'react-router-dom';
|
||||
import JKJamTracksArtistLandingBody from './JKJamTracksArtistLandingBody';
|
||||
|
||||
// This page is not the real entry point into a jamtracks landing page,
|
||||
// as deployed to a server. This is here to facilitate development of the
|
||||
// landing page when running locally.
|
||||
// Note: the real entry point is the JKJamTracksLandingTemplatePage component,
|
||||
// which is used only during build time when generate statice pages as files.
|
||||
const JKJamTracksArtistLanding = () => {
|
||||
const { original_artist_slug } = useParams();
|
||||
return (
|
||||
<div>
|
||||
<JKJamTracksArtistLandingBody original_artist_slug={original_artist_slug} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default JKJamTracksArtistLanding
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import React, {useContext} from "react";
|
||||
import { BrowserRouter as Router, ReactDOM } from "react-router-dom";
|
||||
|
||||
import JKJamTracksArtistLandingBody from "./JKJamTracksArtistLandingBody";
|
||||
import AppContext from "../../context/Context";
|
||||
import {useResponsive} from "@farfetch/react-context-responsive";
|
||||
import {Navbar} from "reactstrap";
|
||||
import {topNavbarBreakpoint} from "../../config";
|
||||
import Logo from "../navbar/Logo";
|
||||
import {BrowserQueryProvider} from "../../context/BrowserQuery";
|
||||
import Footer from "../footer/JKFooter";
|
||||
|
||||
const ArtistTemplatePage = ({ original_artist_slug, artist, songs}) => {
|
||||
console.log('ArtistTemplatePage', original_artist_slug, artist);
|
||||
|
||||
const {
|
||||
isFluid,
|
||||
isTopNav,
|
||||
} = useContext(AppContext);
|
||||
|
||||
const { greaterThan } = useResponsive();
|
||||
|
||||
const paddingClass = greaterThan.sm ? "px-6" : "px-1";
|
||||
|
||||
return (
|
||||
<Router location={location} context={{}}>
|
||||
<div className={isFluid ? 'container-fluid' : 'container'}>
|
||||
<div className="content">
|
||||
<Navbar
|
||||
light
|
||||
color="white"
|
||||
className={`navbar-glass fs--1 font-weight-semi-bold row navbar-top sticky-kit mb-3 py-3 ${paddingClass}`}
|
||||
expand={isTopNav && topNavbarBreakpoint}
|
||||
>
|
||||
<Logo at="navbar-top" id="topLogo" width={240}/>
|
||||
</Navbar>
|
||||
<div className={`pt-3 row ${paddingClass}`}>
|
||||
<BrowserQueryProvider>
|
||||
<JKJamTracksArtistLandingBody artist={artist} original_artist_slug={original_artist_slug} songs={songs}
|
||||
provided_jam_track={null}/>
|
||||
</BrowserQueryProvider>
|
||||
</div>
|
||||
{/* <div className='px-6 row'> */}
|
||||
<Footer/>
|
||||
{/* </div> */}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default ArtistTemplatePage;
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ const BodyComponent = ({
|
|||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="jamtrack-landing-body">
|
||||
<UserAuth path={"/"}>
|
||||
<AppDataProvider>
|
||||
<JamTrackPreviewProvider>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useContext } from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import PublicRoutes from './JKPublicRoutes';
|
||||
import { BrowserQueryProvider } from '../context/BrowserQuery';
|
||||
import Logo from '../components/navbar/Logo';
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ import JKForum from '../components/public/help/JKForum';
|
|||
import JKUnsubscribe from '../components/public/JKUnsubscribe';
|
||||
import JKDownloads from '../components/public/JKDownloads';
|
||||
import JKDownloadsLegacy from '../components/public/JKDownloadsLegacy';
|
||||
import JKJamTracksLanding from '../components/jamtracks/JKJamTracksLanding';
|
||||
import JKJamTracksLanding from '../components/jamtracks/JKJamTracksLandingDev';
|
||||
import JKJamTracksArtistLanding from '../components/jamtracks/JKJamTracksArtistLandingDev';
|
||||
|
||||
const JKPublicRoutes = ({ match: { url } }) => (
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ const JKPublicRoutes = ({ match: { url } }) => (
|
|||
<Route path={`${url}/downloads`} exact component={JKDownloads} />
|
||||
<Route path={`${url}/downloads-legacy`} exact component={JKDownloadsLegacy} />
|
||||
<Route path={`${url}/backing-tracks/:artist/:song`} component={JKJamTracksLanding} />
|
||||
<Route path={`${url}/backing-tracks/:artist`} component={JKJamTracksLanding} />
|
||||
<Route path={`${url}/backing-tracks/:artist`} component={JKJamTracksArtistLanding} />
|
||||
|
||||
{/*Redirect*/}
|
||||
<Redirect to="/errors/404" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue