Upload Video


Creator Studio

Upload a video like a real creator platform

Build the title, description, ticker focus, thumbnail, visibility, and SEO signals before you publish. When you hit publish, StockMarketLoop creates the watch page and recommendation-ready video record automatically.

Stock Market LoopConnect. Learn. Share. Grow.
Stock Market Loop
Join StockmarketloopSign in to post, vote sentiment, save watchlists and view member tools.

Creator Studio

Upload a video like a real creator platform

Build the title, description, ticker focus, thumbnail, visibility, and SEO signals before you publish. When you hit publish, StockMarketLoop creates the watch page and recommendation-ready video record automatically.

' + watchUrl + '', embedCode: '' }; } function errors() { var out = []; if (!draft.filePreviewName && !draft.upload) { out.push('Choose a video file first.'); } if (!String(draft.title || '').trim()) { out.push('Add a title before publishing.'); } if (String(draft.title || '').length > 100) { out.push('Titles must stay under 100 characters.'); } if (!String(draft.description || '').trim()) { out.push('Add a description so the watch page and search previews are not empty.'); } if (String(draft.description || '').length > 5000) { out.push('Descriptions must stay under 5,000 characters.'); } if (!cashtag(draft.ticker)) { out.push('Add a primary ticker so recommendations and internal linking can classify the video.'); } if (tokenList(draft.hashtags, true).length > 5) { out.push('Use five hashtags or fewer.'); } if (draft.visibility === 'scheduled' && (!draft.publishDate || !draft.publishTime)) { out.push('Scheduled videos need a publish date and time.'); } return out; } function statusMarkup(tone, text) { return '
' + esc(text || '') + '
'; } function fileSummaryMarkup() { if (!draft.filePreviewName && !draft.upload) { return ''; } var mime = (draft.upload && draft.upload.mime) || ''; var label = mime && mime.indexOf('video/') === 0 ? 'Video' : 'Upload'; return '' + '
' + '
' + esc(label) + '
' + '
' + ' ' + esc(draft.filePreviewName || (draft.upload && draft.upload.name) || 'Selected video') + '' + ' ' + esc(draft.filePreviewSize || 'Ready to upload') + '' + ' The publish step will create the Chart post, watch page, and recommendation-ready video record.' + '
' + '
'; } function thumbPreviewMarkup() { var src = draft.thumbUrl || cfg.defaultThumbnail || ''; return '' + '
' + (src ? 'Thumbnail preview' : '
Upload a 16:9 image
') + '
'; } function stepMarkup() { var data = metadataOutputs(); switch (draft.step) { case 0: return '' + '
' + '
' + ' Choose the video file first' + '

This uploader keeps the flow similar to a creator platform: file first, then title, ticker, thumbnail, search metadata, visibility, and publish.

' + ' ' + ' ' + fileSummaryMarkup() + '
' + '
'; case 1: return '' + '
' + '
' + '
Keep it sharp and market-specific.
' + '
This becomes a cashtag on the watch page and helps recommendations.
' + '
' + '
The first two lines do most of the work for SEO, previews, and recommendations.
' + '
' + '
' + '
' + '
' + '
' + thumbPreviewMarkup() + '
' + '
Use a 16:9 image so the watch page, search cards, and shares stay clean.
' + '
Tags help with aliases, misspellings, and topic clustering.
' + '
Use 2 to 4 focused hashtags.
' + '
' + '
' + '
'; case 2: return '' + '
' + '
Leave blank to auto-generate from the title and ticker.
' + '
The final watch page URL is set on publish. This preview helps you shape the share copy now.
' + '
' + '
Search preview
' + '
' + esc(data.searchPreview) + '
' + '
' + codeBlock('VideoObject JSON-LD', data.videoJsonLd) + codeBlock('Sitemap line', data.sitemapLine) + codeBlock('Embed code', data.embedCode) + '
'; case 3: default: return '' + '
' + '
' + '
' + '
This becomes the real watch page after publish.
' + '
' + (draft.visibility === 'scheduled' ? '
' : '') + '
' + '

Helps creators and sites reuse the watch page player cleanly.

' + '

Comments help engagement and recommendation quality.

' + '
' + ' ' + '
'; } } function codeBlock(title, value) { return '' + '
' + '
' + esc(title) + '
' + '
' + esc(value) + '
' + '
'; } function previewMarkup() { var outputs = metadataOutputs(); return '' + '
' + '
' + ((draft.thumbUrl || cfg.defaultThumbnail) ? 'Watch page preview' : '') + '
' + '
' + ' ' + esc(outputs.seoTitle) + '' + '
' + esc(outputs.watchUrl) + '
' + '
' + esc(outputs.metaDescription || 'Add a title and description to see how the preview will look.') + '
' + '
' + (outputs.tickerTag ? '' + esc(outputs.tickerTag) + '' : '') + outputs.hashtags.map(function (tag) { return '' + esc(tag) + ''; }).join('') + '
' + '
' + '
'; } function sideMarkup() { var outputs = metadataOutputs(); return '' + '
' + '

Watch page preview

' + '

This is the metadata package your watch page, shares, and recommendation engine will use after publish.

' + previewMarkup() + '
' + '
' + '

Recommendation signals

' + '

Ticker: ' + esc(outputs.tickerTag || 'Missing') + '

' + '

Category: ' + esc(draft.category || 'Missing') + '

' + '

Hashtags: ' + esc(outputs.hashtags.join(' ') || 'Missing') + '

' + '

Visibility: ' + esc((draft.visibility || 'public').replace(/^./, function (letter) { return letter.toUpperCase(); })) + '

' + '
' + '
' + '

Why this page matters

' + '

The old route was dead. This upload studio now gathers the metadata the StockMarketLoop watch pages, search previews, and video recommendation service actually need.

' + '
'; } function loggedOutMarkup() { return '' + '
' + '

Sign in to upload

' + '

Creators need to be signed in before they can upload a video, attach the right title and ticker metadata, and generate a watch page that can actually be crawled.

' + ' Sign in' + '
'; } function renderStatus() { if (publishing) { return statusMarkup('warn', 'Publishing video, creating the Chart post, and generating the watch page...'); } var issues = errors(); if (!issues.length) { return statusMarkup('good', 'Metadata looks healthy. This upload is ready to publish into the watch-page system.'); } return statusMarkup('warn', issues[0]); } function render() { normalizeDraft(); if (!cfg.loggedIn) { root.innerHTML = loggedOutMarkup(); return; } var issues = errors(); root.innerHTML = '' + '
' + '
' + '
' + '
' + stepButton(0, 'File', 'Choose and stage the video') + stepButton(1, 'Details', 'Title, ticker, description, thumbnail') + stepButton(2, 'SEO & indexing', 'Search preview, structured data, watch URL') + stepButton(3, 'Visibility', 'Public, unlisted, private, scheduled') + '
' + '
' + stepMarkup() + (issues.length ? '
' + issues.map(function (issue) { return '' + esc(issue) + ''; }).join('') + '
' : '') + '
' + ' ' + '
' + '
' + ' ' + '
'; } function stepButton(index, title, text) { return '' + ''; } function humanSize(bytes) { var size = Number(bytes || 0); if (!size) { return ''; } if (size >= 1024 * 1024 * 1024) { return (size / (1024 * 1024 * 1024)).toFixed(2) + ' GB'; } if (size >= 1024 * 1024) { return (size / (1024 * 1024)).toFixed(1) + ' MB'; } return Math.round(size / 1024) + ' KB'; } function uploadAsset(endpoint, kind, file) { var normalizedKind = kind === 'thumbnail' ? 'photo' : kind; var form = new FormData(); form.append('kind', normalizedKind); form.append('media', file, file.name); function send(url) { return fetch(url, { method: 'POST', credentials: 'same-origin', cache: 'no-store', headers: { 'Accept': 'application/json', 'X-WP-Nonce': cfg.nonce || '' }, body: form }).then(function (response) { return response.json().catch(function () { return {}; }).then(function (payload) { if (!response.ok) { var error = new Error(payload.message || 'Upload failed.'); error.code = payload.code || ''; error.status = response.status; throw error; } return payload; }); }); } return send(endpoint).catch(function (error) { if (cfg.pluginUploadEndpoint && endpoint !== cfg.pluginUploadEndpoint && (error.status === 404 || error.code === 'rest_no_route')) { return send(cfg.pluginUploadEndpoint); } throw error; }); } function publishViaPlugin(uploaded) { var outputs = metadataOutputs(); return fetch(cfg.pluginPublishEndpoint, { method: 'POST', credentials: 'same-origin', cache: 'no-store', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'X-WP-Nonce': cfg.nonce || '' }, body: JSON.stringify({ title: draft.title || uploaded.videoUpload.title || draft.filePreviewName || 'StockMarketLoop video', seo_title: outputs.seoTitle || draft.title || '', description: draft.description || '', ticker: String(draft.ticker || '').replace(/^\$/, ''), visibility: draft.visibility || 'public', video_url: uploaded.videoUpload.url, video_name: uploaded.videoUpload.name || draft.filePreviewName || '', video_mime: uploaded.videoUpload.mime || '', thumbnail_url: (uploaded.thumbUpload && uploaded.thumbUpload.url) || draft.thumbUrl || '', tags: outputs.tags || [], hashtags: outputs.hashtags || [] }) }).then(function (response) { return response.json().catch(function () { return {}; }).then(function (payload) { if (!response.ok) { throw new Error(payload.message || 'Publish failed.'); } return payload; }); }); } function publishPayload(videoUpload, thumbUpload) { var outputs = metadataOutputs(); var tickerTag = outputs.tickerTag; var textParts = []; if (draft.title) { textParts.push(draft.title); } if (draft.description) { textParts.push(draft.description); } if (tickerTag) { textParts.push(tickerTag); } if (outputs.hashtags.length) { textParts.push(outputs.hashtags.join(' ')); } var media = { url: videoUpload.url, type: 'video', name: draft.title || videoUpload.title || draft.filePreviewName, mime: videoUpload.mime, title: draft.title || videoUpload.title || draft.filePreviewName, description: draft.description || '', visibility: draft.visibility === 'scheduled' ? 'public' : draft.visibility, thumbnail_url: (thumbUpload && thumbUpload.url) || draft.thumbUrl || '', watch_url: draft.publishedWatchUrl || '', uploadWizardComplete: true }; return { user_id: cfg.userId, text: textParts.filter(Boolean).join('\n\n'), media: media }; } function publishVideo() { var issues = errors(); if (issues.length || publishing || !draft.file) { render(); return; } publishing = true; render(); uploadAsset(cfg.chartMediaEndpoint, 'video', draft.file) .then(function (videoUpload) { draft.upload = videoUpload; if (draft.thumbFile) { return uploadAsset(cfg.chartMediaEndpoint, 'thumbnail', draft.thumbFile).then(function (thumbUpload) { return { videoUpload: videoUpload, thumbUpload: thumbUpload }; }); } return { videoUpload: videoUpload, thumbUpload: null }; }) .then(function (uploaded) { return fetch(cfg.profileChartEndpoint, { method: 'POST', credentials: 'same-origin', cache: 'no-store', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'X-WP-Nonce': cfg.nonce || '' }, body: JSON.stringify(publishPayload(uploaded.videoUpload, uploaded.thumbUpload)) }).then(function (response) { return response.json().catch(function () { return {}; }).then(function (payload) { if (!response.ok) { var error = new Error(payload.message || 'Publish failed.'); error.code = payload.code || ''; error.status = response.status; throw error; } return payload; }); }); }) .catch(function (error) { if (cfg.pluginPublishEndpoint && (error.status === 404 || error.code === 'rest_no_route')) { return publishViaPlugin({ videoUpload: draft.upload || {}, thumbUpload: draft.thumbUrl ? { url: draft.thumbUrl } : null }); } throw error; }) .then(function (payload) { var watchUrl = (payload && payload.post && payload.post.media && payload.post.media.watch_url) || (payload && payload.watch_url) || ''; draft.publishedWatchUrl = watchUrl || ''; saveDraft(); if (watchUrl) { window.location.href = watchUrl; return; } publishing = false; render(); }) .catch(function (error) { publishing = false; window.alert(error && error.message ? error.message : 'The video could not be published.'); render(); }); } function bind() { root.addEventListener('click', function (event) { var step = event.target.closest('[data-step]'); if (step) { draft.step = Number(step.getAttribute('data-step') || 0); saveDraft(); render(); return; } var action = event.target.closest('[data-action]'); if (action) { var kind = action.getAttribute('data-action'); if (kind === 'back') { draft.step = Math.max(0, draft.step - 1); } else if (kind === 'next') { draft.step = Math.min(3, draft.step + 1); } else if (kind === 'save') { saveDraft(); } saveDraft(); render(); return; } if (event.target.closest('[data-upload-pick]')) { var fileInput = root.querySelector('[data-upload-file]'); if (fileInput) { fileInput.click(); } return; } if (event.target.closest('[data-thumb-pick]')) { var thumbInput = root.querySelector('[data-thumb-file]'); if (thumbInput) { thumbInput.click(); } return; } var publish = event.target.closest('[data-publish]'); if (publish) { publishVideo(); return; } var copy = event.target.closest('[data-copy]'); if (copy && navigator.clipboard) { navigator.clipboard.writeText(copy.getAttribute('data-copy') || ''); copy.textContent = 'Copied'; window.setTimeout(function () { copy.textContent = 'Copy'; }, 1200); } }); root.addEventListener('input', function (event) { var field = event.target.closest('[data-field]'); if (field) { draft[field.getAttribute('data-field')] = field.value; saveDraft(); return; } var check = event.target.closest('[data-check]'); if (check) { draft[check.getAttribute('data-check')] = !!check.checked; saveDraft(); return; } }); root.addEventListener('change', function (event) { var fileInput = event.target.closest('[data-upload-file]'); if (fileInput && fileInput.files && fileInput.files[0]) { var file = fileInput.files[0]; draft.file = file; draft.filePreviewName = file.name; draft.filePreviewSize = humanSize(file.size); if (!draft.title) { draft.title = file.name.replace(/\.[^.]+$/, '').replace(/[-_]+/g, ' ').trim(); } saveDraft(); render(); return; } var thumbInput = event.target.closest('[data-thumb-file]'); if (thumbInput && thumbInput.files && thumbInput.files[0]) { draft.thumbFile = thumbInput.files[0]; var reader = new FileReader(); reader.onload = function () { draft.thumbUrl = String(reader.result || ''); saveDraft(); render(); }; reader.readAsDataURL(draft.thumbFile); return; } var field = event.target.closest('[data-field]'); if (field) { draft[field.getAttribute('data-field')] = field.value; saveDraft(); render(); } }); } function boot() { if (booted) { return true; } root = resolveRoot(); if (!root) { return false; } cfg = window.smlVideoUploadStudioConfig || readConfigFromScripts() || cfg || {}; normalizeDraft(); bind(); render(); booted = true; return true; } if (!boot()) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot, { once: true }); } var bootAttempts = 0; var bootTimer = window.setInterval(function () { bootAttempts += 1; if (boot() || bootAttempts > 20) { window.clearInterval(bootTimer); } }, 250); } })();