mirror of
https://github.com/olegvodyanov/instalinks.git
synced 2025-12-20 07:57:04 +03:00
219 lines
6.2 KiB
JavaScript
219 lines
6.2 KiB
JavaScript
const newLinkInput = document.getElementById('newLinkInput');
|
||
const addLinkBtn = document.getElementById('addLinkBtn');
|
||
const newLinksContainer = document.getElementById('newLinksContainer');
|
||
const watchedLinksContainer = document.getElementById('watchedLinksContainer');
|
||
|
||
const PER_PAGE = 8;
|
||
let currentPage = 1;
|
||
let linksData = [];
|
||
|
||
function extractReelId(url) {
|
||
// Example: https://www.instagram.com/reel/ABC123xyz/
|
||
const match = url.match(/instagram\.com\/reel\/([a-zA-Z0-9_-]+)/);
|
||
return match ? match[1] : null;
|
||
}
|
||
|
||
function loadLinks() {
|
||
const cacheKeyWatched = `links_cache_page_${currentPage}_per_${PER_PAGE}&watched='True'`;
|
||
const cachedWatched = localStorage.getItem(cacheKeyWatched);
|
||
|
||
const cacheKey = `links_cache_page_${currentPage}_per_${PER_PAGE}`;
|
||
const cached = localStorage.getItem(cacheKey);
|
||
|
||
if (cachedWatched) {
|
||
const data = JSON.parse(cachedWatched);
|
||
linksData = data.results;
|
||
renderPaginatedList(
|
||
linksData,watchedLinksContainer,true,data.page,data.pages
|
||
);
|
||
}
|
||
|
||
if (cached) {
|
||
const data = JSON.parse(cached);
|
||
linksData = data.results;
|
||
renderPaginatedList(
|
||
linksData,newLinksContainer,false,data.page,data.pages
|
||
);
|
||
}
|
||
|
||
// Always fetch fresh data in the background
|
||
fetch(`/api/links/?page=${currentPage}&per_page=${PER_PAGE}&watched='True'`)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
localStorage.setItem(cacheKeyWatched, JSON.stringify(data));
|
||
if (!cachedWatched) {
|
||
linksData = data.results;
|
||
renderPaginatedList(
|
||
linksData,watchedLinksContainer,true,data.page,data.pages
|
||
);
|
||
}
|
||
})
|
||
.catch(err => console.error(err));
|
||
|
||
fetch(`/api/links/?page=${currentPage}&per_page=${PER_PAGE}`)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
localStorage.setItem(cacheKey, JSON.stringify(data));
|
||
if (!cached) {
|
||
linksData = data.results;
|
||
renderPaginatedList(
|
||
linksData,newLinksContainer,false,data.page,data.pages
|
||
);
|
||
}
|
||
})
|
||
.catch(err => console.error(err));
|
||
}
|
||
|
||
function renderPaginatedList(linkList, container, isWatched, page, totalPages) {
|
||
container.innerHTML = '';
|
||
|
||
const row = document.createElement('div');
|
||
row.className = 'row gy-4';
|
||
|
||
linkList
|
||
.filter(link => link.watched === isWatched)
|
||
.forEach(link => {
|
||
const column = document.createElement('div');
|
||
column.className = 'col-12 col-sm-6 col-md-4 col-lg-3';
|
||
column.appendChild(createLinkElement(link, isWatched));
|
||
row.appendChild(column);
|
||
});
|
||
|
||
container.appendChild(row);
|
||
|
||
// Pagination controls
|
||
if (totalPages > 1) {
|
||
const navigation = document.createElement('div');
|
||
navigation.className = 'd-flex justify-content-center mt-4 gap-2';
|
||
|
||
const previousBtn = document.createElement('button');
|
||
previousBtn.innerText = '← Previous';
|
||
previousBtn.className = 'btn btn-outline-primary';
|
||
previousBtn.disabled = page <= 1;
|
||
previousBtn.onclick = () => {
|
||
currentPage--;
|
||
loadLinks();
|
||
};
|
||
|
||
const nextBtn = document.createElement('button');
|
||
nextBtn.innerText = 'Next →';
|
||
nextBtn.className = 'btn btn-outline-primary';
|
||
nextBtn.disabled = page >= totalPages;
|
||
nextBtn.onclick = () => {
|
||
currentPage++;
|
||
loadLinks();
|
||
};
|
||
|
||
navigation.appendChild(previousBtn);
|
||
navigation.appendChild(nextBtn);
|
||
container.appendChild(navigation);
|
||
}
|
||
|
||
reinitializeInstagramEmbeds();
|
||
}
|
||
|
||
// Create a DOM element for a single link
|
||
function createLinkElement(link, isWatched) {
|
||
const wrapper = document.createElement('div');
|
||
wrapper.className = 'mb-auto';
|
||
|
||
const blockquote = document.createElement('blockquote');
|
||
blockquote.className = 'instagram-media';
|
||
blockquote.setAttribute('data-instgrm-permalink', link.url);
|
||
blockquote.style.background = '#FFF';
|
||
blockquote.style.width = '100%';
|
||
|
||
const p = document.createElement('p');
|
||
p.innerText = 'Loading Instagram...';
|
||
blockquote.appendChild(p);
|
||
wrapper.appendChild(blockquote);
|
||
|
||
const btnGroup = document.createElement('div');
|
||
btnGroup.className = 'mt-2 d-flex gap-2';
|
||
|
||
// Button to mark watched if it's not watched
|
||
if (!isWatched) {
|
||
const watchButton = document.createElement('button');
|
||
watchButton.className = 'btn btn-sm btn-secondary';
|
||
watchButton.innerText = 'Mark Watched';
|
||
watchButton.onclick = () => markLinkWatched(link.id);
|
||
btnGroup.appendChild(watchButton);
|
||
}
|
||
|
||
// Delete button
|
||
const deleteButton = document.createElement('button');
|
||
deleteButton.innerText = 'Delete';
|
||
deleteButton.className = 'btn btn-sm btn-danger';
|
||
deleteButton.onclick = () => deleteLink(link.id);
|
||
btnGroup.appendChild(deleteButton);
|
||
|
||
wrapper.appendChild(btnGroup);
|
||
|
||
return wrapper;
|
||
}
|
||
|
||
function deleteLink(linkId) {
|
||
fetch(`/api/links/${linkId}/delete/`, {
|
||
method: 'DELETE'
|
||
})
|
||
.then(response => {
|
||
if (response.ok) {
|
||
linksData = linksData.filter(link => link.id !== linkId);
|
||
currentPage = 1;
|
||
loadLinks();
|
||
reinitializeInstagramEmbeds();
|
||
}
|
||
})
|
||
.catch(err => console.error(err));
|
||
}
|
||
|
||
// Re-run the Instagram embed script after we’ve injected new blockquotes
|
||
function reinitializeInstagramEmbeds() {
|
||
if (window.instgrm) {
|
||
window.instgrm.Embeds.process();
|
||
}
|
||
}
|
||
|
||
// Mark a link as watched
|
||
function markLinkWatched(linkId) {
|
||
fetch(`/api/links/${linkId}/watched/`, {
|
||
method: 'PATCH'
|
||
})
|
||
.then(response => response.json())
|
||
.then(updatedLink => {
|
||
// Update the local array
|
||
const idx = linksData.findIndex(link => link.id === updatedLink.id);
|
||
if (idx !== -1) {
|
||
linksData[idx] = updatedLink;
|
||
}
|
||
loadLinks();
|
||
reinitializeInstagramEmbeds();
|
||
})
|
||
.catch(err => console.error(err));
|
||
}
|
||
|
||
// Add new link
|
||
addLinkBtn.addEventListener('click', () => {
|
||
const newUrl = newLinkInput.value.trim();
|
||
if (!newUrl) return;
|
||
|
||
fetch('/api/links/add/', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ url: newUrl })
|
||
})
|
||
.then(response => response.json())
|
||
.then(addedLink => {
|
||
// update local data
|
||
linksData.push(addedLink);
|
||
newLinkInput.value = '';
|
||
currentPage = 1;
|
||
loadLinks();
|
||
reinitializeInstagramEmbeds();
|
||
})
|
||
.catch(err => console.error(err));
|
||
});
|
||
|
||
// On page load
|
||
loadLinks();
|