Compare commits
34 Commits
72dee2de36
...
feature/Fi
| Author | SHA1 | Date | |
|---|---|---|---|
| 17e0e6e526 | |||
|
|
02a3eef5e7 | ||
|
|
11d2ab8c86 | ||
|
|
778c0a2827 | ||
|
|
00e385cdbe | ||
|
|
cf9cc22a1c | ||
|
|
0c5dc17ae6 | ||
|
|
4347543ef7 | ||
|
|
9d51abd9ab | ||
|
|
118443305b | ||
|
|
ab4453487e | ||
|
|
e003d9795b | ||
|
|
e88dbd98cc | ||
|
|
eba447cd06 | ||
|
|
9aec2d3150 | ||
|
|
f2e11f827f | ||
|
|
32b6129ae3 | ||
|
|
94e8ecb60a | ||
|
|
1cf8032be4 | ||
|
|
47033f737d | ||
|
|
0f85d8da56 | ||
|
|
31c2d94e0b | ||
|
|
0848f4a015 | ||
|
|
92958e4c64 | ||
|
|
4f20c08ed0 | ||
|
|
9400c1f917 | ||
|
|
ddbcb4be5e | ||
|
|
20357809a7 | ||
|
|
c1d730dffa | ||
|
|
1dfcf710ff | ||
|
|
d3ffd6c678 | ||
|
|
b294771061 | ||
|
|
a058aa5095 | ||
|
|
fa459026ff |
87
QuickSetup.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Quick Setup
|
||||
|
||||
## user_config.json
|
||||
|
||||
`user_config.json` (in the same folder as `app.js`) is where you put your local configuration overrides. It merges on top of `includes/config.json` — **do not edit `includes/config.json` directly**.
|
||||
|
||||
You only need to include keys you want to override. Copy `user_config.example.json` as a starting point, or start with a minimal file:
|
||||
|
||||
```json
|
||||
{
|
||||
"config": {
|
||||
"service_ip": "192.168.1.x"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The file supports `// line comments` and `/* block comments */`.
|
||||
|
||||
---
|
||||
|
||||
## configurator.js
|
||||
|
||||
`tools/configurator.js` is a command-line tool that sets or deletes individual keys in `user_config.json` without manually editing JSON.
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
node tools/configurator.js <dot.path.key> <value> [--overwrite]
|
||||
node tools/configurator.js <dot.path.key> --delete [--overwrite]
|
||||
```
|
||||
|
||||
- Use `--overwrite` to replace a key that already exists.
|
||||
- Keys are expressed as dot-separated paths (e.g. `config.keys.user_data_key`).
|
||||
|
||||
---
|
||||
|
||||
## Setting service_ip
|
||||
|
||||
`service_ip` tells the box where to connect, this CANNOT be `0.0.0.0`, and must be an address reachable by your box when it connects via your setup. Can be `127.0.0.1` if you are running TouchPPP or WebTV Viewer on the same machine as minisrv.
|
||||
|
||||
```
|
||||
node tools/configurator.js config.service_ip 192.168.1.x --overwrite
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setting user_data_key
|
||||
|
||||
`user_data_key` is used to encrypt user data. It should be a random secret string and **must be set before registering any users**.
|
||||
Changing it after users have registered will require updating the userdata with `tools/update_user_data_key.js`. Making a backup
|
||||
of `SessionStore/accounts` is recommended before running `tools/update_user_data_key.js`, it is pretty resilent against corruption, but just in case.
|
||||
|
||||
```
|
||||
node tools/configurator.js config.keys.user_data_key YOUR_RANDOM_SECRET --overwrite
|
||||
```
|
||||
|
||||
To generate a random key:
|
||||
```
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
## Disabling a standard service
|
||||
|
||||
You can disable a configured service by setting the `disabled: true` flag for that service. For example, to disable `wtv-admin`:
|
||||
|
||||
```
|
||||
node tools/configurator.js services.wtv-admin.disabled true
|
||||
```
|
||||
|
||||
|
||||
## Enabling a disabled service
|
||||
|
||||
You can disable a configured service by setting the `disabled: false` flag for that service. For example, to enable `pc_services`:
|
||||
|
||||
```
|
||||
node tools/configurator.js services.pc_services.disabled false
|
||||
```
|
||||
|
||||
## Custom service pages
|
||||
|
||||
You can place your custom pages in `UserServiceVault/servicename/page.js`. For example, to override `wtv-home:/home`, you would create
|
||||
`UserServiceVault/wtv-home/home.js`, and the server will automatically prioritize your page. You can mix and match service vaults, accessing
|
||||
resources in the standard service vault within your custom pages.
|
||||
|
||||
## Updating minisrv
|
||||
|
||||
You can `git pull`, or extract a new archive over the existing folder. If you followed the directions and kept your changes in `user_config.json` and `UserServiceVault`,
|
||||
then you can update minisrv without worrying about breakage or losing data. Do pay attention to the console, and if any deprecreations appear, fix them before updating to the version listed in the notice.
|
||||
@@ -9,7 +9,7 @@ This open source server is in beta status. Use at your own risk.
|
||||
### Note:
|
||||
- This has nothing to do with streaming video.
|
||||
- This is a server for the MSNTV (formerly WebTV) set-top box, and its various emulators.
|
||||
- This does not support MSNTV2.
|
||||
- This does not yet fully support MSNTV2.
|
||||
|
||||
### Current status:
|
||||
- DB-less flat file client session store and registration system
|
||||
|
||||
@@ -11,7 +11,7 @@ const process = wtvshared.process;
|
||||
const util = wtvshared.util;
|
||||
const nunjucks = require('nunjucks');
|
||||
const {serialize, unserialize} = require('php-serialize');
|
||||
const {spawn} = require('child_process');
|
||||
const {spawn, spawnSync} = require('child_process');
|
||||
const http = require('follow-redirects').http;
|
||||
const httpx = require(classPath + "/HTTPX.js");
|
||||
const { URL } = require('url');
|
||||
@@ -27,6 +27,7 @@ const WTVClientSessionData = require(classPath + "/WTVClientSessionData.js");
|
||||
const WTVMime = require(classPath + "/WTVMime.js");
|
||||
const WTVFlashrom = require(classPath + "/WTVFlashrom.js");
|
||||
const WTVImage = require(classPath + "/WTVImage.js");
|
||||
const WTVAudioProxy = require(classPath + "/WTVAudioProxy.js");
|
||||
const vm = require('vm');
|
||||
const debug = require('debug')('app');
|
||||
const express = require('express');
|
||||
@@ -37,6 +38,30 @@ const protocolServers = [];
|
||||
|
||||
const minisrv_config = wtvshared.getMiniSrvConfig(); // snatches minisrv_config
|
||||
const wtvmime = new WTVMime(minisrv_config);
|
||||
const wtvAudioProxy = new WTVAudioProxy(minisrv_config);
|
||||
|
||||
function validateAudioProxy() {
|
||||
if (!wtvAudioProxy || !wtvAudioProxy.isEnabled()) return;
|
||||
|
||||
try {
|
||||
const check = spawnSync(wtvAudioProxy.config.ffmpegPath, ['-hide_banner', '-version'], {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
if (check.error || check.status !== 0) {
|
||||
console.warn(` # AudioProxy disabled: ffmpeg not found or failed to execute at '${wtvAudioProxy.config.ffmpegPath}'.`);
|
||||
if (check.error) console.warn(` # AudioProxy ffmpeg error: ${check.error.message}`);
|
||||
wtvAudioProxy.config.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(` * AudioProxy enabled: transcoding audio to ${wtvAudioProxy.config.bitrate} ${wtvAudioProxy.config.sampleRate}Hz mono MP3.`);
|
||||
} catch (error) {
|
||||
console.warn(` # AudioProxy disabled: ffmpeg validation failed: ${error.message}`);
|
||||
wtvAudioProxy.config.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
.on('SIGTERM', shutdown('SIGTERM'))
|
||||
@@ -203,24 +228,43 @@ function getServiceString(service_name, overrides = {}) {
|
||||
}
|
||||
|
||||
|
||||
const DEPRECIATED_CONFIG_PATH = path.join(__dirname, 'includes', 'depreciated.json');
|
||||
|
||||
function loadDepreciatedPatterns() {
|
||||
try {
|
||||
if (!fs.existsSync(DEPRECIATED_CONFIG_PATH)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const raw = fs.readFileSync(DEPRECIATED_CONFIG_PATH, 'utf8');
|
||||
const parsed = JSON.parse(raw);
|
||||
|
||||
if (!Array.isArray(parsed) || parsed.length === 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const mapped = parsed
|
||||
.filter((entry) => entry && typeof entry.pattern === 'string')
|
||||
.map((entry) => ({
|
||||
id: entry.id || entry.pattern,
|
||||
pattern: new RegExp(entry.pattern, entry.flags || 'g'),
|
||||
message: entry.message || 'Deprecated API usage found',
|
||||
removeVersion: entry.removeVersion || 'unknown',
|
||||
replacement: entry.replacement || null
|
||||
}));
|
||||
|
||||
return mapped.length > 0 ? mapped : {};
|
||||
} catch (error) {
|
||||
console.warn('Failed to load includes/depreciated.json, using fallback deprecation patterns:', error.message);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Deprecation warnings configuration
|
||||
const deprecationWarnings = {
|
||||
// Array of deprecated patterns with their details
|
||||
patterns: [
|
||||
{
|
||||
// Example deprecations - you can modify these as needed
|
||||
pattern: /session\_data\.hasCap\s*\(/g,
|
||||
message: "session_data.hasCap() is deprecated and will be removed",
|
||||
removeVersion: "0.9.80",
|
||||
replacement: "Use session_data.capabilities.get() instead"
|
||||
},
|
||||
{
|
||||
pattern: /(?<!wtvshared\.)getServiceString\s*\(/g,
|
||||
message: "getServiceString() is deprecated and will be removed",
|
||||
removeVersion: "0.9.80",
|
||||
replacement: "Use wtvshared.getServiceString() instead"
|
||||
}
|
||||
],
|
||||
patterns: loadDepreciatedPatterns(),
|
||||
|
||||
// Enable/disable deprecation warnings globally
|
||||
enabled: true,
|
||||
@@ -338,7 +382,7 @@ const runScriptInVM = function (script_data, user_contextObj = {}, privileged =
|
||||
"service_vaults": service_vaults,
|
||||
"service_deps": service_deps,
|
||||
"ssid_sessions": ssid_sessions,
|
||||
"moveArrayKey": wtvshared.moveArrayKey,
|
||||
"moveArrayKey": wtvshared.moveArrayKey, // deprecated - use wtvshared.moveArrayKey() instead
|
||||
"cwd": (filename) ? path.dirname(filename) : __dirname, // current working directory
|
||||
|
||||
// Our prototype overrides
|
||||
@@ -468,7 +512,7 @@ async function handleCGI(executable, cgi_file, socket, request_headers, vault, s
|
||||
env.SERVER_PORT = request_data.port;
|
||||
env.SERVER_ADDR = request_data.host;
|
||||
env.SERVER_NAME = request_data.host;
|
||||
if ((minisrv_config.services[socket.service_name] && minisrv_config.services[socket.service_name].hide_minisrv_version) || minisrv_config.config.hide_server_version) {
|
||||
if (minisrv_config.config.hide_minisrv_version) {
|
||||
env.SERVER_SOFTWARE = "NodeJS; minisrv";
|
||||
} else {
|
||||
// Full version
|
||||
@@ -1256,7 +1300,7 @@ minisrv-no-mail-count: true`;
|
||||
}
|
||||
}
|
||||
|
||||
async function sendToClient(socket, headers_obj, data = null) {
|
||||
async function sendToClient(socket, headers_obj, data = null, throttle = 0) {
|
||||
let headers = "";
|
||||
let content_length = 0;
|
||||
const eol = "\n";
|
||||
@@ -1272,6 +1316,7 @@ async function sendToClient(socket, headers_obj, data = null) {
|
||||
if (socket.destroy) socket.destroy();
|
||||
return;
|
||||
}
|
||||
const isWebTVClient = Boolean(socket.ssid && ssid_sessions[socket.ssid]);
|
||||
if (!socket.res) {
|
||||
wtv_connection_close = (headers_obj["wtv-connection-close"]) ? true : false;
|
||||
if (typeof (headers_obj["wtv-connection-close"]) !== 'undefined') delete headers_obj["wtv-connection-close"];
|
||||
@@ -1367,24 +1412,22 @@ async function sendToClient(socket, headers_obj, data = null) {
|
||||
delete headers_obj['minisrv-no-last-modified'];
|
||||
}
|
||||
|
||||
if (minisrv_config.config.image_decoder && minisrv_config.config.image_decoder.enabled) {
|
||||
if (isWebTVClient && minisrv_config.config.image_decoder && minisrv_config.config.image_decoder.enabled) {
|
||||
const contype_key = wtvshared.getCaseInsensitiveKey('content-type', headers_obj);
|
||||
let pngOpts = {};
|
||||
if (contype_key) {
|
||||
if (minisrv_config.config.image_decoder.image_formats && minisrv_config.config.image_decoder.image_formats.includes(headers_obj[contype_key].toLowerCase())) {
|
||||
const convertOpts = {
|
||||
jpegQuality: minisrv_config.config.image_decoder.jpg_quality,
|
||||
type: imageArtemisType
|
||||
type: imageArtemisType,
|
||||
imgopts: minisrv_config.config.image_decoder.image_options || null
|
||||
};
|
||||
|
||||
if (minisrv_config.config.image_decoder.max_height > 0) convertOpts.maxHeight = minisrv_config.config.image_decoder.max_height;
|
||||
if (minisrv_config.config.image_decoder.max_width > 0) convertOpts.maxWidth = minisrv_config.config.image_decoder.max_width;
|
||||
if (minisrv_config.config.image_decoder.png_opts) {
|
||||
pngOpts = minisrv_config.config.image_decoder.png_opts;
|
||||
}
|
||||
|
||||
const sourceData = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
||||
try {
|
||||
const converted = await WTVImage.ImageToWebTV(sourceData, convertOpts, pngOpts);
|
||||
const converted = await WTVImage.ImageToWebTV(sourceData, convertOpts);
|
||||
data = converted.data;
|
||||
content_length = data.length;
|
||||
var i=0;
|
||||
@@ -1392,7 +1435,7 @@ async function sendToClient(socket, headers_obj, data = null) {
|
||||
// Image is too big, try to reduce quality
|
||||
if (i < minisrv_config.config.image_decoder.max_quality_tries) {
|
||||
convertOpts.jpegQuality -= minisrv_config.config.image_decoder.jpeg_interval;
|
||||
var converted2 = await WTVImage.ImageToWebTV(sourceData, convertOpts);
|
||||
var converted2 = await WTVImage.ImageToWebTV(sourceData, convertOpts, pngOpts);
|
||||
data = converted2.data;
|
||||
content_length = data.length;
|
||||
i++;
|
||||
@@ -1421,6 +1464,27 @@ async function sendToClient(socket, headers_obj, data = null) {
|
||||
}
|
||||
}
|
||||
|
||||
if (isWebTVClient && wtvAudioProxy && wtvAudioProxy.isEnabled()) {
|
||||
const contype_key = wtvshared.getCaseInsensitiveKey('content-type', headers_obj);
|
||||
if (contype_key && wtvAudioProxy.shouldProxy(headers_obj[contype_key])) {
|
||||
try {
|
||||
const transformResult = await wtvAudioProxy.transformIfNeeded(headers_obj, data);
|
||||
headers_obj = transformResult.headers;
|
||||
data = transformResult.data;
|
||||
content_length = Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data || '');
|
||||
} catch (e) {
|
||||
console.error('Audio proxy error:', e.message);
|
||||
headers_obj = {
|
||||
"Status": "413 Audio Too Long",
|
||||
"Content-type": "text/plain"
|
||||
};
|
||||
data = (e.code === 'AUDIO_TOO_LONG') ?
|
||||
`Audio exceeds maximum allowed duration of ${wtvAudioProxy.config.maxDurationSeconds} seconds.` :
|
||||
`Audio proxy failure: ${e.message}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if client can do compression, see if its worth enabling
|
||||
// small files actually get larger, so don't compress them
|
||||
@@ -1545,7 +1609,7 @@ async function sendToClient(socket, headers_obj, data = null) {
|
||||
if (!xpower && socket.service_name) {
|
||||
// add X-Powered-By header if not WebTV and not already set
|
||||
xpower = 'X-Powered-By';
|
||||
if (minisrv_config.services[socket.service_name].hide_minisrv_version) {
|
||||
if (minisrv_config.config.hide_minisrv_version) {
|
||||
// Don't report version
|
||||
if (!socket.ssid) headers_obj[xpower] = "NodeJS; minisrv";
|
||||
} else {
|
||||
@@ -1556,7 +1620,7 @@ async function sendToClient(socket, headers_obj, data = null) {
|
||||
// delete if webtv
|
||||
if (socket.ssid) delete headers_obj[xpower];
|
||||
if (socket.service_name) {
|
||||
if (minisrv_config.services[socket.service_name].hide_minisrv_version) {
|
||||
if (minisrv_config.config.hide_minisrv_version) {
|
||||
// Don't report version
|
||||
if (!socket.ssid) headers_obj[xpower] = headers_obj[xpower] + "; NodeJS; minisrv";
|
||||
} else {
|
||||
@@ -1614,64 +1678,98 @@ async function sendToClient(socket, headers_obj, data = null) {
|
||||
let toClient = null;
|
||||
if (typeof data === 'string') {
|
||||
toClient = headers + eol + data;
|
||||
sendToSocket(socket, Buffer.from(toClient));
|
||||
sendToSocket(socket, Buffer.from(toClient), throttle);
|
||||
} else if (typeof data === 'object') {
|
||||
let verbosity_mod = (headers_obj["wtv-encrypted"] === 'true') ? " encrypted response" : "";
|
||||
if (socket_sessions[socket.id].secure_headers === true) {
|
||||
// encrypt headers
|
||||
if (minisrv_config.config.debug_flags.quiet) verbosity_mod += " with encrypted headers";
|
||||
const enc_headers = socket_sessions[socket.id].wtvsec.Encrypt(1, headers + eol);
|
||||
sendToSocket(socket, new Buffer.from(concatArrayBuffer(enc_headers, data)));
|
||||
sendToSocket(socket, new Buffer.from(concatArrayBuffer(enc_headers, data)), throttle);
|
||||
} else {
|
||||
sendToSocket(socket, new Buffer.from(concatArrayBuffer(Buffer.from(headers + eol), data)));
|
||||
sendToSocket(socket, new Buffer.from(concatArrayBuffer(Buffer.from(headers + eol), data)), throttle);
|
||||
}
|
||||
if (minisrv_config.config.debug_flags.quiet) console.debug(" * Sent" + verbosity_mod + " " + headers_obj.Status + " to client (Content-Type:", headers_obj['Content-type'], "~", headers_obj['Content-length'], "bytes)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function sendToSocket(socket, data) {
|
||||
async function sendToSocket(socket, data, throttle = 0) {
|
||||
const chunk_size = 16384;
|
||||
let can_write = true;
|
||||
let close_socket = false;
|
||||
let expected_data_out = 0;
|
||||
while ((socket.bytesWritten === 0 || socket.bytesWritten !== expected_data_out) && can_write) {
|
||||
if (expected_data_out === 0) expected_data_out = data.byteLength + (socket_sessions[socket.id].socket_total_written || 0);
|
||||
if (socket.bytesWritten === expected_data_out) break;
|
||||
if (!throttle || throttle <= 0) {
|
||||
let can_write = true;
|
||||
let close_socket = false;
|
||||
let expected_data_out = 0;
|
||||
while ((socket.bytesWritten === 0 || socket.bytesWritten !== expected_data_out) && can_write) {
|
||||
if (expected_data_out === 0) expected_data_out = data.byteLength + (socket_sessions[socket.id].socket_total_written || 0);
|
||||
if (socket.bytesWritten === expected_data_out) break;
|
||||
|
||||
const data_left = (expected_data_out - socket.bytesWritten);
|
||||
// buffer size = lesser of chunk_size or size remaining
|
||||
const buffer_size = (data_left >= chunk_size) ? chunk_size : data_left;
|
||||
if (buffer_size < 0) {
|
||||
socket.destroy();
|
||||
close_socket = true;
|
||||
break;
|
||||
const data_left = (expected_data_out - socket.bytesWritten);
|
||||
// buffer size = lesser of chunk_size or size remaining
|
||||
const buffer_size = (data_left >= chunk_size) ? chunk_size : data_left;
|
||||
if (buffer_size < 0) {
|
||||
socket.destroy();
|
||||
close_socket = true;
|
||||
break;
|
||||
}
|
||||
const offset = (data.byteLength - data_left);
|
||||
const chunk = new Buffer.alloc(buffer_size);
|
||||
data.copy(chunk, 0, offset, (offset + buffer_size));
|
||||
can_write = socket.write(chunk);
|
||||
if (!can_write) {
|
||||
socket.once('drain', function () {
|
||||
sendToSocket(socket, data, throttle);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
const offset = (data.byteLength - data_left);
|
||||
const chunk = new Buffer.alloc(buffer_size);
|
||||
data.copy(chunk, 0, offset, (offset + buffer_size));
|
||||
can_write = socket.write(chunk);
|
||||
if (socket.bytesWritten === expected_data_out || close_socket) {
|
||||
socket_sessions[socket.id].socket_total_written = socket.bytesWritten;
|
||||
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
|
||||
if (socket_sessions[socket.id].header_buffer) delete socket_sessions[socket.id].header_buffer;
|
||||
if (socket_sessions[socket.id].secure_buffer) delete socket_sessions[socket.id].secure_buffer;
|
||||
if (socket_sessions[socket.id].buffer) delete socket_sessions[socket.id].buffer;
|
||||
if (socket_sessions[socket.id].headers) delete socket_sessions[socket.id].headers;
|
||||
if (socket_sessions[socket.id].post_data) delete socket_sessions[socket.id].post_data;
|
||||
if (socket_sessions[socket.id].post_data_length) delete socket_sessions[socket.id].post_data_length;
|
||||
if (socket_sessions[socket.id].post_data_percents_shown) delete socket_sessions[socket.id].post_data_percents_shown;
|
||||
socket.setTimeout(minisrv_config.config.socket_timeout * 1000);
|
||||
if (socket_sessions[socket.id] && socket_sessions[socket.id].close_me) socket.end();
|
||||
if (socket_sessions[socket.id].destroy_me) socket.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let offset = 0;
|
||||
while (offset < data.byteLength) {
|
||||
const buffer_size = Math.min(chunk_size, data.byteLength - offset);
|
||||
const chunk = Buffer.alloc(buffer_size);
|
||||
data.copy(chunk, 0, offset, offset + buffer_size);
|
||||
offset += buffer_size;
|
||||
|
||||
const can_write = socket.write(chunk);
|
||||
if (!can_write) {
|
||||
socket.once('drain', function () {
|
||||
sendToSocket(socket, data);
|
||||
});
|
||||
break;
|
||||
await new Promise(resolve => socket.once('drain', resolve));
|
||||
}
|
||||
|
||||
if (offset < data.byteLength) {
|
||||
const delay_ms = Math.max(1, Math.round((buffer_size * 8) / throttle * 1000));
|
||||
await new Promise(resolve => setTimeout(resolve, delay_ms));
|
||||
}
|
||||
}
|
||||
if (socket.bytesWritten === expected_data_out || close_socket) {
|
||||
socket_sessions[socket.id].socket_total_written = socket.bytesWritten;
|
||||
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
|
||||
if (socket_sessions[socket.id].header_buffer) delete socket_sessions[socket.id].header_buffer;
|
||||
if (socket_sessions[socket.id].secure_buffer) delete socket_sessions[socket.id].secure_buffer;
|
||||
if (socket_sessions[socket.id].buffer) delete socket_sessions[socket.id].buffer;
|
||||
if (socket_sessions[socket.id].headers) delete socket_sessions[socket.id].headers;
|
||||
if (socket_sessions[socket.id].post_data) delete socket_sessions[socket.id].post_data;
|
||||
if (socket_sessions[socket.id].post_data_length) delete socket_sessions[socket.id].post_data_length;
|
||||
if (socket_sessions[socket.id].post_data_percents_shown) delete socket_sessions[socket.id].post_data_percents_shown;
|
||||
socket.setTimeout(minisrv_config.config.socket_timeout * 1000);
|
||||
if (socket_sessions[socket.id] && socket_sessions[socket.id].close_me) socket.end();
|
||||
if (socket_sessions[socket.id].destroy_me) socket.destroy();
|
||||
}
|
||||
|
||||
socket_sessions[socket.id].socket_total_written = socket.bytesWritten;
|
||||
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
|
||||
if (socket_sessions[socket.id].header_buffer) delete socket_sessions[socket.id].header_buffer;
|
||||
if (socket_sessions[socket.id].secure_buffer) delete socket_sessions[socket.id].secure_buffer;
|
||||
if (socket_sessions[socket.id].buffer) delete socket_sessions[socket.id].buffer;
|
||||
if (socket_sessions[socket.id].headers) delete socket_sessions[socket.id].headers;
|
||||
if (socket_sessions[socket.id].post_data) delete socket_sessions[socket.id].post_data;
|
||||
if (socket_sessions[socket.id].post_data_length) delete socket_sessions[socket.id].post_data_length;
|
||||
if (socket_sessions[socket.id].post_data_percents_shown) delete socket_sessions[socket.id].post_data_percents_shown;
|
||||
socket.setTimeout(minisrv_config.config.socket_timeout * 1000);
|
||||
if (socket_sessions[socket.id] && socket_sessions[socket.id].close_me) socket.end();
|
||||
if (socket_sessions[socket.id].destroy_me) socket.destroy();
|
||||
}
|
||||
|
||||
function concatArrayBuffer(buffer1, buffer2) {
|
||||
@@ -2406,6 +2504,8 @@ else console.log(" * Shenanigans disabled");
|
||||
if (minisrv_config.config.image_decoder.enabled) console.log(" * WebTV Unsupported images will be processed and converted for WebTV clients");
|
||||
else console.log(" * WebTV Unsupported images will not be processed, and sent to client as-is");
|
||||
|
||||
validateAudioProxy();
|
||||
|
||||
ports.sort();
|
||||
pc_ports.sort();
|
||||
|
||||
@@ -2602,4 +2702,13 @@ if (bind_ports.length > 0) console.log(` * Started WTVP Server on port${bind_por
|
||||
if (pc_bind_ports.length > 0) console.log(` * Started HTTP Server on port${pc_bind_ports.length !== 1 ? "s" : ""} ` + pc_bind_ports.join(", ") + "...");
|
||||
if (protocolHandledPorts.size > 0) console.log(` * Started ${protocolHandledPorts.size} specialized protocol handler${protocolHandledPorts.size !== 1 ? "s" : ""} on port${protocolHandledPorts.size !== 1 ? "s" : ""} ` + [...protocolHandledPorts].map(([sn, sp, pt]) => `${pt} (${sp.toUpperCase()})`).join(", ") + "...");
|
||||
const listening_ip_string = (minisrv_config.config.bind_ip !== "0.0.0.0") ? "IP: " + minisrv_config.config.bind_ip : "all interfaces";
|
||||
console.log(" * Listening on", listening_ip_string, "~", "Service IP:", service_ip);
|
||||
console.log(" * Listening on", listening_ip_string, "~", "Service IP:", service_ip);
|
||||
|
||||
// Security warning for default user data encryption key
|
||||
if (minisrv_config.config.keys.user_data_key === "PNa$WN7gz}!T=t6X7^=|Ii##CEB~p\\EP") {
|
||||
console.log(" * WARNING: You are using the default user data encryption key. This is not secure, and you should change it in the configuration file before registering any users.");
|
||||
console.log(" * To generate a random key in bash or PowerShell, you can run: node ./tools/configurator.js config.keys.user_data_key $(openssl rand -base64 32)");
|
||||
console.log(" * After changing the key in the user_config, please restart the server.");
|
||||
console.log(" * If you had existing users prior to changing the key, you can run tools/update_user_data_key.js to update existing accounts with the new key.");
|
||||
console.log(" * Making a backup of your user accounts before doing this is highly recommended, in case something goes wrong during the update process.");
|
||||
}
|
||||
23
zefie_wtvp_minisrv/includes/ServiceDeps/msntv2/emac.crt
Normal file
@@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDwzCCAqugAwIBAgIULL+4ofEIwgHwoGgoEJ+mJOmeF4YwDQYJKoZIhvcNAQEF
|
||||
BQAwcDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk9IMRMwEQYDVQQHDApCdXR0IENy
|
||||
YWNrMSAwHgYDVQQKDBdVbmRlcndlYXIgSW5zcGVjdG9yICMxMjEdMBsGA1UECwwU
|
||||
VGhpbmcgTG9va2VyIEV4cGVydHMwIBcNMDAwNDIwMDAwMDAxWhgPMjA2OTA2MDkw
|
||||
MDAwMDFaMHAxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJPSDETMBEGA1UEBwwKQnV0
|
||||
dCBDcmFjazEgMB4GA1UECgwXVW5kZXJ3ZWFyIEluc3BlY3RvciAjMTIxHTAbBgNV
|
||||
BAsMFFRoaW5nIExvb2tlciBFeHBlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEArN5xb8PqUKNNTitGuxyJJxEsWTIt7t7eobSq1+V3hTpknJEspRpb
|
||||
JeD5Ep86pWn4aGoWYT0JU9w4FRJFPaBPAMmLFTIYv1bySlFwna+5J67dAtMm59Pr
|
||||
t3ZSw2dQpads3LGZRSpkY1mv9GC2TVVk/TANWZmWYvEZZ4/2E2YuMJZ6v6gNIY7Y
|
||||
pfJ6F6Q4+d/Dgrvow4E35lmNuM0Y95sdMhKy8HTJ0ecU/bMLKyoXXZyt7LxezT+T
|
||||
w3J2EDVV03lDXZhb0h2ZECmpCAgnKsQ/WmLMjEGeojDQnm+QzTaFHqO0148RMbYN
|
||||
lxURCZVl+keYe1LTHW/K+2f58DeeI0z11wIDAQABo1MwUTAdBgNVHQ4EFgQU0bsp
|
||||
ZOhtJGP0dLS4sdaA4nmQ5ocwHwYDVR0jBBgwFoAU0bspZOhtJGP0dLS4sdaA4nmQ
|
||||
5ocwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEANAV1WNeCggjK
|
||||
eb8kIGkt2R3PMMBy2w+rC4X80xygh+NHU5neJKM1lpq6NLkt5rCBXNCTDb5uPjRv
|
||||
mcrGeIYJYXMy39htjlYgPtfUiQx7e7eq3g1mMHYN26Gr9p7BwJW0QVvaA6zB3lqt
|
||||
HGL7hwQyBCD9P/0sR91sjyLF9mPkaO4sBM5EbrV89LXbD+OPqn10X2Mu4trI3bd4
|
||||
R02Pl0A/rDO/S7bOGc4HGGPSsmgeoapydvkqgnXL497zD1Sv103n96hiuq4Dhurj
|
||||
gfnGxQvEN7MCc31HE2ufkTHjNc62RatseiCLxJE3sBhMl9aaNEhtM3FNDXZnhMbs
|
||||
0/7C2b5kSg==
|
||||
-----END CERTIFICATE-----
|
||||
28
zefie_wtvp_minisrv/includes/ServiceDeps/msntv2/emac.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCs3nFvw+pQo01O
|
||||
K0a7HIknESxZMi3u3t6htKrX5XeFOmSckSylGlsl4PkSnzqlafhoahZhPQlT3DgV
|
||||
EkU9oE8AyYsVMhi/VvJKUXCdr7knrt0C0ybn0+u3dlLDZ1Clp2zcsZlFKmRjWa/0
|
||||
YLZNVWT9MA1ZmZZi8Rlnj/YTZi4wlnq/qA0hjtil8noXpDj538OCu+jDgTfmWY24
|
||||
zRj3mx0yErLwdMnR5xT9swsrKhddnK3svF7NP5PDcnYQNVXTeUNdmFvSHZkQKakI
|
||||
CCcqxD9aYsyMQZ6iMNCeb5DNNoUeo7TXjxExtg2XFREJlWX6R5h7UtMdb8r7Z/nw
|
||||
N54jTPXXAgMBAAECggEAN5W7IfX8FPu9csIllyrAyygRe4jQDjvpmFNwj8VAHj29
|
||||
dj6T/W6xGkfxrtQ2VlPxxRk/ovquUiHAgr4CN6OhY55qs2ENZhD+DXmMXZfQUHtA
|
||||
o5TjsK2K4M4SJLTG0M06CuisYPoVl4CSPGEQnWM0+tiFombpXV0rDwrSVECJ36Mr
|
||||
x/HPoMJQPewBSI4lG2ACQMBmQ+7WQVwl0mprJjIFJYW9BXFRkqmFKSXq6G302VcH
|
||||
VOjiSOF/8BR64worbo9UrpPBPMLZMAW1rwZx50Chwhplben8B2uQNSqrc7Q9ZA3C
|
||||
2XJ8Wi0KCeYmJy+xng3LT22Sdme1UC8YfC9iCsHfaQKBgQDe3sN97UK+WVIgvA8Q
|
||||
+4+rpkUWOy/dCoTzPuxHy4qSTHyF723+URyVkNF/P5EtwKwpIuJ/WMwIyUF0EqLQ
|
||||
0+6HrmqfO5CR+p/2xJhFPHi1qn3uCM8pw5O9i5MjhOr1jM1RQz1xe0rToLiTlq3x
|
||||
sSrYzDmIs61kBH2NKaVp38Oh5QKBgQDGkObMw8Gyn5JT1ewkS0VGDT5bbVK5sptJ
|
||||
KTkaikKTuNV5RLya+7SxnR7rOBWWLN+ZpdQygM8IlUh0TJiTZazUkKUSNv3isIbF
|
||||
rfak10q8Zad6RkaQyyH7GKhBOnMs0z3kqgL0SvNhoIs2KKsE46UoMVE49/C9Ma8Y
|
||||
zbdEBLTtCwKBgQCRJc934d/IDHAadZ/yVYOaLO1trxpbARDZQq+rinozEbE/oVGn
|
||||
gbf2CJ0IHKQ2gfcdy2Rrv68SQdBpAgIbswr0Prmd/rMG/4zSr/LjlKCg3+qn7gDN
|
||||
mFxN4+ruBRDo3syREhOgJsXy0gejx0x9zf6ztz35M9vG+c2y896Q93R3qQKBgA/e
|
||||
AmN4fSD9+V5zqMQZs7ZuVn5N1R97s0b8YVDKnZlaWsyu/ndQB9dtm8vmFmuCuHd5
|
||||
teQ3QNQJwdlxSXv10wLFcDttY4pa2tovFZeEkLdPVDvEI91sLhH3nXJg7lU1qCt+
|
||||
nm/REXPKtXUleM0SN99nWXs47ObhcoGD5tIroh2TAoGBAISazlBBrmnNOavnUzWa
|
||||
Ka2uXk/2txan8Fh9jul0g6GPPsI7Ej3YMf3ccC9iotVugteHrBUK0cNbesydw3J0
|
||||
PIs05XLX0curxoTox2Jeynq+ajy2tnmrDHDfilXdxRt2rsQlobZi3qoJskwPFYhf
|
||||
ssL5LnP78Pv/t2H01jDSpZXu
|
||||
-----END PRIVATE KEY-----
|
||||
27
zefie_wtvp_minisrv/includes/ServiceDeps/msntv2/minisrv.crt
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEqzCCA5OgAwIBAgIQ3Zq6hcFrpKh4v3/G9sTw3DANBgkqhkiG9w0BAQUFADBw
|
||||
MQswCQYDVQQGEwJVUzELMAkGA1UECAwCT0gxEzARBgNVBAcMCkJ1dHQgQ3JhY2sx
|
||||
IDAeBgNVBAoMF1VuZGVyd2VhciBJbnNwZWN0b3IgIzEyMR0wGwYDVQQLDBRUaGlu
|
||||
ZyBMb29rZXIgRXhwZXJ0czAgFw0wMDAxMDExMjAwMDBaGA8yMDk5MTIzMTIzNTk1
|
||||
OVowUTEpMCcGA1UEAxMgaGVhZHdhaXRlci50cnVzdGVkLm1zbnR2Lm1zbi5jb20x
|
||||
FzAVBgNVBAoTDlplZmllIE5ldHdvcmtzMQswCQYDVQQGEwJVUzCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAMtl9J068AFSHykffAlcpspq3D7mE7fFRoyf
|
||||
+tQCM3Wy7PqJvDAegoI4Zf/QdToTJMS6dkcsEx+dgD01VKJ1B0RdHbg6rFQfymc4
|
||||
GKyNk6tuqp7YQqElCUc91oFz4pJaJaOYaNBqkAG3MfTg+tSoBXl2YyjPrT0TPhXX
|
||||
1Cm7BuFZORqNhvTdf33QXzgCQVso9U5X9YBgDaiTcu55etjFKUBEYhSYwTHmennA
|
||||
FWOjY7ux6HFXBfKAz1QeCE6+corl5+6srCfh7Uz3ZFV9vntEYnyzbJuo6gR5P7GI
|
||||
IYsygkADQAETHivl6GxeB7SEUfYLnfrZFwZc235tUz7USBdg3gcCAwEAAaOCAVww
|
||||
ggFYMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMB
|
||||
MIIBJwYDVR0RBIIBHjCCARqCIGhlYWR3YWl0ZXIudHJ1c3RlZC5tc250di5tc24u
|
||||
Y29tghcqLnRydXN0ZWQubXNudHYubXNuLmNvbYINbXNudHYubXNuLmNvbYIWbWFp
|
||||
bC5zZXJ2aWNlcy5saXZlLmNvbYIObG9naW4ubGl2ZS5jb22CEXBvcHRpbWl6ZS5t
|
||||
c24uY29tghFmYXZvcml0ZXMubXNuLmNvbYIRbWVzc2VuZ2VyLm1zbi5jb22CEWxp
|
||||
dmVmaWxlc3RvcmUuY29tghZ1c2Vycy5zdG9yYWdlLmxpdmUuY29tgglnLm1zbi5j
|
||||
b22CF21zbmlhbG9naW4ucGFzc3BvcnQuY29tgg1taW5pc3J2LmxvY2Fsgg8qLm1p
|
||||
bmlzcnYubG9jYWwwDQYJKoZIhvcNAQEFBQADggEBAAGEINTBTrkbpO0CJPv9w4Nj
|
||||
IMuOSZETA7uXWyPwoLBIa57yTjNEVvWmjAc2nnrI3D6ijLMiF1eDIEsP4DI/qfMs
|
||||
J82cS/IOIxXCmReU132NaZ6mSNEZx9QDkz/R8rFq5jKPRYSeguZSsWDxYlaQsbRr
|
||||
qxQsKkRIOpm5pIOA/UT2gwV0L84a/NHXHNfc+CnPvvy7R9kmUC0XynsqU3lkj4Ah
|
||||
SNZOgYyWkGWW7AytQWnMxyWm+xQjG4Fwl1Os9en4qwCK0ADyMCQyG3O68Gffu2go
|
||||
YciXaJquI52fEKDQV4mDxy4B1V8BQ3ywm1iGebLzLgrKK7xPucUU5fqz7v2IUIs=
|
||||
-----END CERTIFICATE-----
|
||||
27
zefie_wtvp_minisrv/includes/ServiceDeps/msntv2/minisrv.key
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAy2X0nTrwAVIfKR98CVymymrcPuYTt8VGjJ/61AIzdbLs+om8
|
||||
MB6Cgjhl/9B1OhMkxLp2RywTH52APTVUonUHRF0duDqsVB/KZzgYrI2Tq26qnthC
|
||||
oSUJRz3WgXPiklolo5ho0GqQAbcx9OD61KgFeXZjKM+tPRM+FdfUKbsG4Vk5Go2G
|
||||
9N1/fdBfOAJBWyj1Tlf1gGANqJNy7nl62MUpQERiFJjBMeZ6ecAVY6Nju7HocVcF
|
||||
8oDPVB4ITr5yiuXn7qysJ+HtTPdkVX2+e0RifLNsm6jqBHk/sYghizKCQANAARMe
|
||||
K+XobF4HtIRR9gud+tkXBlzbfm1TPtRIF2DeBwIDAQABAoIBAADoPGfDhQfq4IyA
|
||||
gVjRvhHmDLbTgOACp1aZbUPeNKUmpKVWniCOA+GZZ2V1ZEIOwGaH0sVtF8xXmZeF
|
||||
5UUKOS7GLL7b6CJB6z2vNt3CJ35av03d3UI2iSzCEYxadd0jcMqJGfwsyLKkdgd6
|
||||
rDO5m7ikdtT0qpGjEQi46AKkCZseSdIZqtgm1t0NupbXuBKbR13N6iNOr6eVnEpZ
|
||||
tTrwIvw/OZ3Wf9tVW0DzjB1ejUYXCYAd6mHskMRrNfu/11x2pyXMHOSl24sVZxHe
|
||||
Dxe+cYjw61/5pMMBq6ZQ61SPvAWZbIOA/PINHIUjisIGxpeqluz0zb+SLLrZnBe5
|
||||
i9WEHsUCgYEA5lKEc5w02/n9+6wZCK/sPWhNJF3cPw2E0O+kqHPWLx2qPNhKf2Zh
|
||||
8RycdVCnCcEXVQedYnNpBeAktMNGxAR9IhiVhfwiG0dFYXNUHBIHgVBZqtOeW8sS
|
||||
uy4/fOw/qCCLWDfnDaozj8RnKsvu6zLm4c73Q4FEr4R6rk4EjfsGA90CgYEA4hMD
|
||||
9PBdIWAYapP2FRangOmP50YNQVznrmDsfFlm2vh3aFrx83f0IFjYxeUI7OdTjkk3
|
||||
7m5pEeV/liQwB/D7uXF+gNoUQab61QRhuKd58TbQELJkeBwevUb3rWVZ3LiFNNVB
|
||||
vcunKTsL4qEADw56qMaczuZ27xXwatgUVtOdbTMCgYAmOA0ojgQreIlPyNgCnAas
|
||||
jfE3Fqgkgl7GuO1u0oH5IYgNPqrmBxw7gU7pHLALK1Ju1qukGZiU1APjRwAoKMKG
|
||||
9ONi71rNgf8eU5/iZI+AQtAOS71caA88pkj8tss9X+Efi2840kRqF+IytNJ5juHH
|
||||
GKvpNLssEOS2pdWVpdDytQKBgF47WNne2qLPwD2kYN1XbQhh0lavL1VAWV2pDsmi
|
||||
Jio9iOAZkGJQbJSTFAAgwICmx4A2arbalLcd9vlpKhAVVYdtlDI3NFxNMp5ZzjW+
|
||||
sShnFYDwKsqZxgJVM2W2KifDTdrAzT9ERO/9qa2UOEcOXPg+mRvwmkB735NZb9jl
|
||||
KehbAoGBANXDltYtJh28hMopP2sZUEx/4A2fnGjVMxBmpSsrk6irz5u/wdhimlDP
|
||||
+JHZZXrb/OTU2BjCPjCCOj953XUqsCpBvWgGdX8uab0O4Gg8x8ucu/K6/kp0X0jN
|
||||
EWQYaMAXJlLQM+k7bXrABNIGu8BF3JzC9oYjlKiFpLqNOQpfHdbK
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -1,15 +1,17 @@
|
||||
const minisrv_service_file = true;
|
||||
|
||||
const title = minisrv_config.config.hide_minisrv_version ? "zefie's minisrv PC Services" : `zefie minisrv v${minisrv_config.version} PC Services`;
|
||||
|
||||
headers = `200 OK
|
||||
Content-Type: text/html`
|
||||
|
||||
data = `<html>
|
||||
<head>
|
||||
<title>zefie minisrv v${minisrv_config.version}</title>
|
||||
<title>${title}</title>
|
||||
</head>
|
||||
<body bgcolor="#000000" text="#449944">
|
||||
<p>
|
||||
Welcome to the zefie minisrv v${minisrv_config.version} PC Services
|
||||
Welcome to ${title}
|
||||
</p>
|
||||
<hr>
|
||||
<a href="/viewergen/">WebTV Viewer Generator</a><br>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
const minisrv_service_file = true;
|
||||
|
||||
headers = `200 OK
|
||||
Content-type: text/html`;
|
||||
|
||||
data = `<HTML>
|
||||
<HEAD>
|
||||
<title id="title"></title>
|
||||
</HEAD>
|
||||
<body>
|
||||
<iframe id=checkmail style="display:none"></iframe>
|
||||
<script language="javascript">
|
||||
var tvShell = new ActiveXObject("MSNTV.TVShell");
|
||||
function IsNightlyEnabled() {
|
||||
var taskScheduler = tvShell.TaskScheduler;
|
||||
var updateTask = null;
|
||||
for (var i = 0; ((i < taskScheduler.Count) && (updateTask == null)); i++) {
|
||||
if (taskScheduler.Item(i).Caller == 'NightlyUpdate') {
|
||||
updateTask = taskScheduler.Item(i);
|
||||
}
|
||||
}
|
||||
if (updateTask != null) {
|
||||
return(true);
|
||||
}
|
||||
else {
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
function GotoBoxCheck() {
|
||||
var url = 'https://sg1.trusted.msntv.msn.com/connection/GatePage.aspx?phase=BoxCheck&purpose=Authorize';
|
||||
var parms='';
|
||||
parms += 'BoxId=' + tvShell.SystemInfo.BoxIDService + '&';
|
||||
parms += 'WANProvider=' + tvShell.ConnectionManager.WANProvider + '&';
|
||||
parms += 'version=' + encodeURIComponent(tvShell.SystemInfo.LastVersion) + '&';
|
||||
if ((tvShell.ConnectionManager.MSNIAManager != null) && (tvShell.ConnectionManager.MSNIAManager.CurrentConnector != null)) parms += 'ConnectorName=' + encodeURIComponent(tvShell.ConnectionManager.MSNIAManager.CurrentConnector.Name) + '&';
|
||||
if (tvShell.UserManager.CurrentUser != null) parms += 'domain=' + encodeURIComponent(tvShell.UserManager.CurrentUser.Domain) + '&';
|
||||
parms += 'NumRedirects=0&';
|
||||
parms += 'NightlyEnabled=' + IsNightlyEnabled() + '&';
|
||||
parms += 'x=y';
|
||||
var myPanel = tvShell.PanelManager.Item('service');
|
||||
if (myPanel) myPanel.PostToURL(url, parms);
|
||||
}
|
||||
var progressPanel = tvShell.PanelManager.Item('progress');
|
||||
function SetProgress(text, percent) {
|
||||
if (progressPanel) {
|
||||
progressPanel.Document.SetProgressText(text);
|
||||
progressPanel.Document.SetProgressPercent(percent);
|
||||
}
|
||||
}
|
||||
function IsServicePanel() {
|
||||
if ((window.name == null) || ((window.name != null) && (window.name.toLowerCase() != 'service'))) {
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
function DontContinue() {
|
||||
var currentUser = tvShell.UserManager.CurrentUser;
|
||||
if (currentUser != null && currentUser.IsAuthorized) {
|
||||
window.location.replace(tvShell.UserManager.CurrentUser.ServiceList.Item('home::home').URL);
|
||||
}
|
||||
else {
|
||||
tvShell.ConnectionManager.ServiceState = 'ReSignIn';
|
||||
}
|
||||
}
|
||||
if (!IsServicePanel()) {
|
||||
DontContinue();
|
||||
}
|
||||
else {
|
||||
tvShell.MeteringManager.Stop();
|
||||
SetProgress('Please wait while we sign you into MSN TV.', 10);
|
||||
GotoBoxCheck();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</HTML>
|
||||
`;
|
||||
@@ -0,0 +1,444 @@
|
||||
const minisrv_service_file = true;
|
||||
const crypto = require('crypto');
|
||||
|
||||
// Sorry Zef :kek
|
||||
// https://git.computernewb.com/yellows111/msnp-wiki/src/branch/master/docs/services/rst.md
|
||||
// the RST_ cookie stuff was code that was temp until we had proper token authentication
|
||||
const NS = {
|
||||
SOAP: "http://schemas.xmlsoap.org/soap/envelope/",
|
||||
WSSE: "http://schemas.xmlsoap.org/ws/2003/06/secext",
|
||||
WSP: "http://schemas.xmlsoap.org/ws/2002/12/policy",
|
||||
WSU: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
|
||||
WSA: "http://schemas.xmlsoap.org/ws/2004/03/addressing",
|
||||
WST: "http://schemas.xmlsoap.org/ws/2004/04/trust",
|
||||
PSF: "http://schemas.microsoft.com/Passport/SoapServices/SOAPFault",
|
||||
ENC: "http://www.w3.org/2001/04/xmlenc#",
|
||||
DS: "http://www.w3.org/2000/09/xmldsig#"
|
||||
};
|
||||
|
||||
function getCookie(cookieString, name) {
|
||||
if (!cookieString) return null;
|
||||
const match = cookieString.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));
|
||||
return match ? decodeURIComponent(match[1]) : null;
|
||||
}
|
||||
|
||||
function setCookie(name, value, options = {}) {
|
||||
const cookie = `${name}=${encodeURIComponent(value)}`;
|
||||
const path = options.path || '/';
|
||||
const expires = options.expires || '';
|
||||
return `${cookie}; path=${path}${expires ? `; expires=${expires}` : ''}`;
|
||||
}
|
||||
|
||||
function formatDateTime(dt) {
|
||||
return dt.toISOString().replace(/\.\d{3}Z$/, 'Z');
|
||||
}
|
||||
|
||||
function getClientIP() {
|
||||
const forwarded = request_headers['x-forwarded-for'];
|
||||
if (forwarded) {
|
||||
const ips = forwarded.split(',');
|
||||
return ips[0].trim();
|
||||
}
|
||||
return request_headers['x-real-ip'] || '127.0.0.1';
|
||||
}
|
||||
|
||||
function generateRandomToken(userId, appliesTo, isLegacy = false) {
|
||||
const timestamp = Date.now();
|
||||
const randomPart = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
if (isLegacy) {
|
||||
const tokenData = `${userId}|${appliesTo}|${timestamp}|${randomPart}`;
|
||||
return crypto.createHash('sha256').update(tokenData).digest('hex');
|
||||
} else {
|
||||
const tokenData = {
|
||||
uid: userId,
|
||||
app: appliesTo,
|
||||
ts: timestamp,
|
||||
rand: randomPart,
|
||||
ver: '1.0'
|
||||
};
|
||||
return Buffer.from(JSON.stringify(tokenData)).toString('base64');
|
||||
}
|
||||
}
|
||||
|
||||
function extractXmlValue(xml, elementName) {
|
||||
if (!xml) return null;
|
||||
|
||||
const patterns = [
|
||||
new RegExp(`<${elementName}>([\\s\\S]*?)</${elementName}>`, 'i'),
|
||||
new RegExp(`<wsse:${elementName}>([\\s\\S]*?)</wsse:${elementName}>`, 'i'),
|
||||
new RegExp(`<wst:${elementName}>([\\s\\S]*?)</wst:${elementName}>`, 'i'),
|
||||
new RegExp(`<ps:${elementName}>([\\s\\S]*?)</ps:${elementName}>`, 'i')
|
||||
];
|
||||
|
||||
for (const regex of patterns) {
|
||||
const match = xml.match(regex);
|
||||
if (match && match[1]) {
|
||||
let value = match[1].trim();
|
||||
value = value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractTokenFromCipherValue(xml) {
|
||||
if (!xml) return null;
|
||||
|
||||
const cipherRegex = /<CipherValue>([\s\S]*?)<\/CipherValue>/gi;
|
||||
let match;
|
||||
let token = null;
|
||||
|
||||
while ((match = cipherRegex.exec(xml)) !== null) {
|
||||
let cipherValue = match[1].trim();
|
||||
if (cipherValue && cipherValue.length > 0) {
|
||||
token = cipherValue;
|
||||
console.log("Found CipherValue token:", token.substring(0, 50) + "...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
function validateTokenAndGetUser(token) {
|
||||
try {
|
||||
let userId = null;
|
||||
let email = null;
|
||||
|
||||
if (request_headers.cookie) {
|
||||
userId = getCookie(request_headers.cookie, 'RST_Auth');
|
||||
email = getCookie(request_headers.cookie, 'RST_Email');
|
||||
if (!email) email = getCookie(request_headers.cookie, 'rst_email');
|
||||
if (!email) email = getCookie(request_headers.cookie, 'rst_username');
|
||||
}
|
||||
|
||||
if (!userId) {
|
||||
userId = crypto.createHash('md5').update(token).digest('hex');
|
||||
email = `user_${userId.substring(0, 8)}@example.com`;
|
||||
}
|
||||
|
||||
console.log(`Token validated - UserId: ${userId}, Email: ${email}`);
|
||||
return { success: true, userId, email };
|
||||
} catch (error) {
|
||||
console.error("Token validation error:", error);
|
||||
return { success: false, userId: null, email: null };
|
||||
}
|
||||
}
|
||||
|
||||
function generateErrorResponse(errorCode, errorText) {
|
||||
const now = formatDateTime(new Date());
|
||||
headers = `Status: 200 OK
|
||||
Content-type: text/xml; charset=utf-8`;
|
||||
|
||||
return `<?xml version="1.0" encoding="utf-8"?>
|
||||
<S:Envelope xmlns:S="${NS.SOAP}" xmlns:psf="${NS.PSF}">
|
||||
<S:Header>
|
||||
<psf:pp>
|
||||
<psf:serverVersion>1</psf:serverVersion>
|
||||
<psf:authstate>0x80048800</psf:authstate>
|
||||
<psf:reqstatus>${errorCode}</psf:reqstatus>
|
||||
<psf:serverInfo Path="Live1" RollingUpgradeState="ExclusiveNew" LocVersion="0" ServerTime="${now}">
|
||||
NOBELLIUM 16.0.30846.6
|
||||
</psf:serverInfo>
|
||||
<psf:cookies></psf:cookies>
|
||||
<psf:response></psf:response>
|
||||
</psf:pp>
|
||||
</S:Header>
|
||||
<S:Body>
|
||||
<S:Fault>
|
||||
<S:Code>
|
||||
<S:Value>S:Sender</S:Value>
|
||||
<S:Subcode>
|
||||
<S:Value>wst:FailedAuthentication</S:Value>
|
||||
</S:Subcode>
|
||||
</S:Code>
|
||||
<S:Reason>
|
||||
<S:Text xml:lang="en-US">Authentication Failure</S:Text>
|
||||
</S:Reason>
|
||||
<S:Detail>
|
||||
<psf:error>
|
||||
<psf:value>${errorCode}</psf:value>
|
||||
<psf:internalerror>
|
||||
<psf:code>0x80041012</psf:code>
|
||||
<psf:text>${errorText}</psf:text>
|
||||
</psf:internalerror>
|
||||
</psf:error>
|
||||
</S:Detail>
|
||||
</S:Fault>
|
||||
</S:Body>
|
||||
</S:Envelope>`;
|
||||
}
|
||||
|
||||
function generateSuccessResponse(requestBody, userId, email, firstName, lastName) {
|
||||
const now = new Date();
|
||||
const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000);
|
||||
|
||||
const createdTime = formatDateTime(now);
|
||||
const expiresTime = formatDateTime(tomorrow);
|
||||
|
||||
const puid = crypto.randomBytes(16).toString('hex').toUpperCase();
|
||||
const cid = crypto.randomBytes(8).toString('hex').toUpperCase();
|
||||
|
||||
const safeFirstName = firstName || email.split('@')[0] || "User";
|
||||
const safeLastName = lastName || "User";
|
||||
const clientIp = getClientIP();
|
||||
|
||||
const rstRegex = /<wst:RequestSecurityToken[\s\S]*?<\/wst:RequestSecurityToken>/gi;
|
||||
const responses = [];
|
||||
let match;
|
||||
let foundRst = false;
|
||||
let rstIndex = 0;
|
||||
|
||||
while ((match = rstRegex.exec(requestBody)) !== null) {
|
||||
foundRst = true;
|
||||
const rstBlock = match[0];
|
||||
|
||||
const addressMatch = rstBlock.match(/<wsa:Address>(.*?)<\/wsa:Address>/i);
|
||||
let appliesTo = addressMatch ? addressMatch[1] : "urn:passport:compact";
|
||||
|
||||
const policyMatch = rstBlock.match(/<wsse:PolicyReference\s+URI="([^"]+)"/i);
|
||||
const policy = policyMatch ? policyMatch[1] : null;
|
||||
|
||||
const isLegacy = appliesTo.includes("Passport.NET");
|
||||
const tokenType = isLegacy ? "urn:passport:legacy" : "urn:passport:compact";
|
||||
const needsProofToken = policy === "MBI_KEY_OLD";
|
||||
|
||||
const token = generateRandomToken(userId, appliesTo, isLegacy);
|
||||
const tokenId = isLegacy ? `BinaryDAToken${rstIndex}` : `Compact${rstIndex}`;
|
||||
const binarySecret = crypto.randomBytes(32).toString('base64');
|
||||
|
||||
let requestedSecurityToken;
|
||||
if (isLegacy) {
|
||||
requestedSecurityToken = `
|
||||
<wst:RequestedSecurityToken>
|
||||
<EncryptedData xmlns="${NS.ENC}" Id="${tokenId}" Type="http://www.w3.org/2001/04/xmlenc#Element">
|
||||
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
|
||||
<ds:KeyInfo xmlns:ds="${NS.DS}">
|
||||
<ds:KeyName>http://Passport.NET/STS</ds:KeyName>
|
||||
</ds:KeyInfo>
|
||||
<CipherData>
|
||||
<CipherValue>${token}</CipherValue>
|
||||
</CipherData>
|
||||
</EncryptedData>
|
||||
</wst:RequestedSecurityToken>`;
|
||||
} else {
|
||||
let tokenValue = `t=${token}`;
|
||||
if (needsProofToken) {
|
||||
tokenValue += `&p=profile`;
|
||||
}
|
||||
requestedSecurityToken = `
|
||||
<wst:RequestedSecurityToken>
|
||||
<wsse:BinarySecurityToken Id="${tokenId}">${tokenValue}</wsse:BinarySecurityToken>
|
||||
</wst:RequestedSecurityToken>`;
|
||||
}
|
||||
|
||||
let responseXml = `
|
||||
<wst:RequestSecurityTokenResponse>
|
||||
<wst:TokenType>${tokenType}</wst:TokenType>
|
||||
<wsp:AppliesTo xmlns:wsa="${NS.WSA}">
|
||||
<wsa:EndpointReference>
|
||||
<wsa:Address>${appliesTo}</wsa:Address>
|
||||
</wsa:EndpointReference>
|
||||
</wsp:AppliesTo>
|
||||
<wst:LifeTime>
|
||||
<wsu:Created>${createdTime}</wsu:Created>
|
||||
<wsu:Expires>${expiresTime}</wsu:Expires>
|
||||
</wst:LifeTime>
|
||||
${requestedSecurityToken}
|
||||
<wst:RequestedTokenReference>
|
||||
<wsse:KeyIdentifier ValueType="${tokenType}"/>
|
||||
<wsse:Reference URI="#${tokenId}"/>
|
||||
</wst:RequestedTokenReference>`;
|
||||
|
||||
if (needsProofToken || isLegacy) {
|
||||
responseXml += `
|
||||
<wst:RequestedProofToken>
|
||||
<wst:BinarySecret>${binarySecret}</wst:BinarySecret>
|
||||
</wst:RequestedProofToken>`;
|
||||
}
|
||||
|
||||
responseXml += `
|
||||
</wst:RequestSecurityTokenResponse>`;
|
||||
|
||||
responses.push(responseXml);
|
||||
rstIndex++;
|
||||
}
|
||||
|
||||
if (!foundRst) {
|
||||
const defaultToken = generateRandomToken(userId, "urn:passport:compact", false);
|
||||
responses.push(`
|
||||
<wst:RequestSecurityTokenResponse>
|
||||
<wst:TokenType>urn:passport:compact</wst:TokenType>
|
||||
<wst:RequestedSecurityToken>
|
||||
<wsse:BinarySecurityToken Id="Compact0">t=${defaultToken}</wsse:BinarySecurityToken>
|
||||
</wst:RequestedSecurityToken>
|
||||
<wst:LifeTime>
|
||||
<wsu:Created>${createdTime}</wsu:Created>
|
||||
<wsu:Expires>${expiresTime}</wsu:Expires>
|
||||
</wst:LifeTime>
|
||||
</wst:RequestSecurityTokenResponse>`);
|
||||
}
|
||||
|
||||
headers = `Status: 200 OK
|
||||
Content-type: text/xml; charset=utf-8
|
||||
Set-Cookie: RST_Auth=${userId}; path=/; HttpOnly
|
||||
Set-Cookie: RST_Email=${email}; path=/`;
|
||||
|
||||
return `<?xml version="1.0" encoding="utf-8"?>
|
||||
<S:Envelope xmlns:S="${NS.SOAP}">
|
||||
<S:Header>
|
||||
<psf:pp xmlns:psf="${NS.PSF}">
|
||||
<psf:serverVersion>1</psf:serverVersion>
|
||||
<psf:PUID>${puid}</psf:PUID>
|
||||
<psf:configVersion>16.000.26889.00</psf:configVersion>
|
||||
<psf:uiVersion>3.100.2179.0</psf:uiVersion>
|
||||
<psf:mobileConfigVersion>16.000.26208.0</psf:mobileConfigVersion>
|
||||
<psf:authstate>0x48803</psf:authstate>
|
||||
<psf:reqstatus>0x0</psf:reqstatus>
|
||||
<psf:serverInfo Path="Live1" RollingUpgradeState="ExclusiveNew" LocVersion="0" ServerTime="${now.toISOString()}">
|
||||
NOBELLIUM 16.0.30846.6
|
||||
</psf:serverInfo>
|
||||
<psf:cookies></psf:cookies>
|
||||
<psf:browserCookies>
|
||||
<psf:browserCookie Name="MH" URL="http://www.msn.com">MSFT; path=/; domain=.msn.com; expires=Wed, 30-Dec-2037 16:00:00 GMT</psf:browserCookie>
|
||||
<psf:browserCookie Name="MH" URL="http://www.live.com">MSFT; path=/; domain=.live.com; expires=Wed, 30-Dec-2037 16:00:00 GMT</psf:browserCookie>
|
||||
</psf:browserCookies>
|
||||
<psf:credProperties>
|
||||
<psf:credProperty Name="MainBrandID">MSFT</psf:credProperty>
|
||||
<psf:credProperty Name="IsWinLiveUser">true</psf:credProperty>
|
||||
<psf:credProperty Name="CID">${cid}</psf:credProperty>
|
||||
<psf:credProperty Name="AuthMembername">${email}</psf:credProperty>
|
||||
<psf:credProperty Name="Country">US</psf:credProperty>
|
||||
<psf:credProperty Name="Language">1033</psf:credProperty>
|
||||
<psf:credProperty Name="FirstName">${safeFirstName}</psf:credProperty>
|
||||
<psf:credProperty Name="LastName">${safeLastName}</psf:credProperty>
|
||||
<psf:credProperty Name="Flags">40100643</psf:credProperty>
|
||||
<psf:credProperty Name="IP">${clientIp}</psf:credProperty>
|
||||
</psf:credProperties>
|
||||
<psf:extProperties>
|
||||
<psf:extProperty Name="CID">${cid}</psf:extProperty>
|
||||
</psf:extProperties>
|
||||
<psf:response></psf:response>
|
||||
</psf:pp>
|
||||
</S:Header>
|
||||
<S:Body>
|
||||
<wst:RequestSecurityTokenResponseCollection
|
||||
xmlns:wst="${NS.WST}"
|
||||
xmlns:wsse="${NS.WSSE}"
|
||||
xmlns:wsu="${NS.WSU}"
|
||||
xmlns:wsp="${NS.WSP}"
|
||||
xmlns:psf="${NS.PSF}">
|
||||
${responses.join('\n ')}
|
||||
</wst:RequestSecurityTokenResponseCollection>
|
||||
</S:Body>
|
||||
</S:Envelope>`;
|
||||
}
|
||||
|
||||
|
||||
function rstHandler() {
|
||||
try {
|
||||
|
||||
// Get POST data
|
||||
let requestBody = '';
|
||||
if (request_headers.post_data) {
|
||||
if (Buffer.isBuffer(request_headers.post_data)) {
|
||||
requestBody = request_headers.post_data.toString('utf8');
|
||||
} else if (typeof request_headers.post_data === 'string') {
|
||||
requestBody = request_headers.post_data;
|
||||
} else if (typeof request_headers.post_data === 'object') {
|
||||
requestBody = JSON.stringify(request_headers.post_data);
|
||||
}
|
||||
} else {
|
||||
console.log("No post_data found. Available keys:", Object.keys(request_headers));
|
||||
return generateErrorResponse("0x80048820", "No POST data received");
|
||||
}
|
||||
|
||||
if (!requestBody || requestBody.trim() === '') {
|
||||
console.log("Empty request body");
|
||||
return generateErrorResponse("0x80048820", "Empty request body");
|
||||
}
|
||||
|
||||
// Authentication
|
||||
let email = extractXmlValue(requestBody, 'Username');
|
||||
let password = extractXmlValue(requestBody, 'Password');
|
||||
|
||||
let userId = null;
|
||||
let userEmail = null;
|
||||
let firstName = "User";
|
||||
let lastName = "User";
|
||||
|
||||
if ((!email || !password) && requestBody.includes('CipherValue')) {
|
||||
console.log("No username/password found, trying token authentication...");
|
||||
const token = extractTokenFromCipherValue(requestBody);
|
||||
|
||||
if (token) {
|
||||
const tokenValidation = validateTokenAndGetUser(token);
|
||||
if (tokenValidation.success) {
|
||||
userId = tokenValidation.userId;
|
||||
userEmail = tokenValidation.email;
|
||||
console.log(`Token authentication successful for: ${userEmail} (${userId})`);
|
||||
|
||||
if (request_headers.cookie) {
|
||||
const cookieEmail = getCookie(request_headers.cookie, 'RST_Email');
|
||||
const cookieUsername = getCookie(request_headers.cookie, 'rst_username');
|
||||
if (cookieEmail) userEmail = cookieEmail;
|
||||
if (cookieUsername) firstName = cookieUsername;
|
||||
}
|
||||
} else {
|
||||
console.log("Token validation failed");
|
||||
return generateErrorResponse("0x80048821", "Invalid token");
|
||||
}
|
||||
} else {
|
||||
console.log("No token found in CipherValue");
|
||||
return generateErrorResponse("0x80048820", "Missing credentials/token");
|
||||
}
|
||||
}
|
||||
else if (email && password) {
|
||||
console.log(`Extracted - Email: ${email}, Password: ${password ? '***' : 'empty'}`);
|
||||
|
||||
if (email && email.indexOf('@') < 0) {
|
||||
const domain = (minisrv_config && minisrv_config.config && minisrv_config.config.domain_name) || 'wtv.zefie.com';
|
||||
email = `${email}@${domain}`;
|
||||
}
|
||||
|
||||
userEmail = email;
|
||||
firstName = email.split('@')[0];
|
||||
userId = crypto.createHash('md5').update(email).digest('hex');
|
||||
console.log(`Authentication successful for: ${userEmail} (${userId})`);
|
||||
}
|
||||
else {
|
||||
console.log("Missing both credentials and token");
|
||||
return generateErrorResponse("0x80048820", "Missing credentials/token");
|
||||
}
|
||||
|
||||
if (!userId || !userEmail) {
|
||||
console.log("Failed to get user identity");
|
||||
return generateErrorResponse("0x80048821", "User identity not found");
|
||||
}
|
||||
|
||||
const cookieHeaders = [
|
||||
setCookie('rst_email', userEmail, { path: '/' }),
|
||||
setCookie('rst_username', firstName, { path: '/' }),
|
||||
setCookie('rst_authenticated', 'true', { path: '/', expires: 'Wed, 30-Dec-2037 16:00:00 GMT' })
|
||||
];
|
||||
|
||||
const response = generateSuccessResponse(requestBody, userId, userEmail, firstName, lastName);
|
||||
|
||||
for (const cookie of cookieHeaders) {
|
||||
headers += `\nSet-Cookie: ${cookie}`;
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
} catch (error) {
|
||||
console.error("RST Handler Error:", error);
|
||||
console.error("Error stack:", error.stack);
|
||||
return generateErrorResponse("0x80048820", `Internal error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
let result = rstHandler();
|
||||
if (result) {
|
||||
data = result;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
const minisrv_service_file = true;
|
||||
|
||||
// Wrong email return: <LoginResponse Success="false"><Error Code="e5b"/></LoginResponse>
|
||||
// Wrong Password return: <LoginResponse Success="false"><Error Code="e5a"/></LoginResponse>
|
||||
|
||||
// Example Client request: <LoginRequest><ClientInfo name="MSNTV" version="1.35"/><User><SignInName>example@example.com</SignInName><Password>example</Password><SavePassword>false</SavePassword></User><DAOption>1</DAOption><TargetOption>1</TargetOption></LoginRequest>
|
||||
|
||||
data = `<LoginResponse Success="true"><TnP>t=Disabled&p=Disabled</TnP></LoginResponse>`; // T and P cant be nulled they have to have some content in it
|
||||
|
||||
headers = `200 OK
|
||||
Content-Type: text/xml`;
|
||||
|
||||
console.log(request_headers.query);
|
||||
|
After Width: | Height: | Size: 43 B |
@@ -0,0 +1,528 @@
|
||||
const minisrv_service_file = true;
|
||||
|
||||
// Weather placeholder (static defaults — no live API)
|
||||
const WeatherCity = 'Your City';
|
||||
const WeatherTemp = '72';
|
||||
const WeatherDescription = 'Sunny';
|
||||
const WeatherIcon = '/Home/Weather/26.gif';
|
||||
|
||||
// News headlines
|
||||
const NewsLink1 = '';
|
||||
const NewsLink2 = '';
|
||||
const NewsLink3 = '';
|
||||
const NewsTitle1 = '...';
|
||||
const NewsTitle2 = '...';
|
||||
const NewsTitle3 = '...';
|
||||
|
||||
headers = `200 OK
|
||||
Content-type: text/html`;
|
||||
|
||||
data = `<html xmlns:msntv>
|
||||
<?import namespace="msntv" implementation="Shared/Anduril/HTC/en-us/TruncatedHtml.htc"?>
|
||||
|
||||
<head><title>Home</title>
|
||||
<?import namespace="msntv" implementation="HTC/Shared/CustomButton.htc"?>
|
||||
<?import namespace="msntv" implementation="/Home/Shared/BaseClient/HTCTransforms/en-us/LoopingDIV.htc"?>
|
||||
|
||||
<script src="/Include/2.0.261.900/localhost-1700/Shared/BaseClient/JsTransforms/en-us/PaneHelp.js" language="javascript" defer="true"></script>
|
||||
<link href="/Include/2.0.261.778/localhost-1700/Home/Anduril/CssTransforms/en-us/Home.css" type="text/css" rel="StyleSheet">
|
||||
<script src="/Include/2.0.261.778/localhost-1700/Home/Anduril/JsTransforms/en-us/Home.js" language="javascript"></script>
|
||||
|
||||
<script>
|
||||
var forceReload = false;
|
||||
var l = 'd:' + new Date().valueOf() + '|';
|
||||
function setCookie(name, value) {
|
||||
{
|
||||
var now = new Date();
|
||||
var expires = new Date(now.getFullYear() + 1, now.getMonth(), now.getDate());
|
||||
document.cookie = escape(name) + '=' + escape(value) + ';expires=' + expires.toGMTString() + ';path=/';
|
||||
}
|
||||
}
|
||||
function getCookie(name) {
|
||||
{
|
||||
var str = document.cookie;
|
||||
var arr = str.split('; ');
|
||||
for (var i = arr.length - 1; i >= 0; i--) {
|
||||
{
|
||||
var c = arr[i].split('=');
|
||||
if (c.length != 2)
|
||||
continue;
|
||||
if (unescape(c[0]) == name)
|
||||
return unescape(c[1]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function syncCookie(cookieName, propValue) {
|
||||
{
|
||||
var c = getCookie(cookieName);
|
||||
l += 'g:' + cookieName + ':' + c + '|';
|
||||
if (c != propValue) {
|
||||
{
|
||||
setCookie(cookieName, propValue);
|
||||
l += 's:' + cookieName + ':' + propValue + '|';
|
||||
var check = getCookie(cookieName);
|
||||
if (check == propValue)
|
||||
forceReload = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var d = new Date();
|
||||
var utcOffset = d.getTimezoneOffset();
|
||||
syncCookie('UserUtcOffset', utcOffset);
|
||||
var connSpeed;
|
||||
try { { connSpeed = window.external.ClientCaps.connectionType; } }
|
||||
catch (e) {
|
||||
{
|
||||
connSpeed = "undetected";
|
||||
}
|
||||
}
|
||||
syncCookie('UserConnectionSpeed', connSpeed);
|
||||
try {
|
||||
{
|
||||
top.log(l);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
{
|
||||
}
|
||||
}
|
||||
if (forceReload)
|
||||
location.replace(location.href);
|
||||
</script></head>
|
||||
|
||||
<body>
|
||||
|
||||
<body onload="initPage();" scroll="no" tabindex="-1">
|
||||
|
||||
<div id="focdiv" style="position:absolute;top:314px;left:27px;width:70px;height:70px;" onclick="goToMail();">
|
||||
</div>
|
||||
<script>
|
||||
document.all["focdiv"].focus();
|
||||
|
||||
function handleLoopingDivReady()
|
||||
{
|
||||
document.all["focdiv"].style.display = "none";
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="topdiv">
|
||||
|
||||
<div class="textMenu">
|
||||
<script xmlns:msntvuxp="msntvuxp.microsoft.com">
|
||||
function goToService(serviceName) {window.location = window.external.SafeGetServiceURL(serviceName);}
|
||||
function goToCenter(svcURL) {window.location = svcURL;}
|
||||
</script>
|
||||
|
||||
<div style="position:absolute; left:0px; top:0px" xmlns:msntvuxp="msntvuxp.microsoft.com">
|
||||
<table border="0" class="TextMenuTbl">
|
||||
<tr height="34" style="background-color: transparent;">
|
||||
<td class="leftGradientTD"></td><td class="rightGradientTD">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div style="position:absolute; left:0px; top:0px" xmlns:msntvuxp="msntvuxp.microsoft.com">
|
||||
<table border="0" class="TextMenuTbl">
|
||||
<tr>
|
||||
<td style="background-color: transparent;" width="8">
|
||||
<img height="1" src="/Images/Shared/s.gif" width="8">
|
||||
</td>
|
||||
<td style="background-color: transparent;" align="left" width="162">
|
||||
<a class="TextMenuLink" href="javascript:goToCenter('/Pages/UsingMSNTV/Main');" id="UsingMSNTVLinkID" onblur="umtvHasFocus=false">Using MSN TV</a>
|
||||
</td>
|
||||
|
||||
<div>
|
||||
<span style="position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<td style="background-color: transparent;" align="left" width="115">
|
||||
<a class="TextMenuLink" href="javascript:void(window.open(' ', 'signout', 'msntv:panel'));" id="SignoutLinkID">Sign Out</a>
|
||||
</td>
|
||||
|
||||
<div>
|
||||
<span style="position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;"></span>
|
||||
</div>
|
||||
<td style="background-color: transparent;" align="left" width="106">
|
||||
<a class="TextMenuLink" href="javascript:goToService('UAM::UAMbase');" id="AccountLinkID">Account</a>
|
||||
</td>
|
||||
<div>
|
||||
<span style="position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;">
|
||||
</span>
|
||||
</div>
|
||||
<td style="background-color: transparent;" align="left" width="109">
|
||||
<a class="TextMenuLink" href="javascript:goToService('settings::mainindex');" id="SettingsLinkID">Settings</a>
|
||||
</td>
|
||||
<div><span style="position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;">
|
||||
</span>
|
||||
</div>
|
||||
<td style="background-color: transparent;" align="left" width="78">
|
||||
<a href='javascript:CallPaneHelp(PH_TOC);' id="HelpLinkID">
|
||||
|
||||
<table><tr>
|
||||
<td valign="middle" class="TextMenuLinkSimulation">Help</td>
|
||||
<td valign="middle" width="30" height="20">
|
||||
<span id="helpIcon" style='src:url(msntv:/Shared/Images/Icon_Help_RelatedLink.png);'></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</a>
|
||||
</td>
|
||||
<div>
|
||||
<span style="position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;">
|
||||
</span>
|
||||
</div>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="infoPaneDiv">
|
||||
|
||||
<div class="promoImgDiv">
|
||||
<div style="position:absolute; left:0px; top:0px">
|
||||
<img id="PromoImageID" width="178" height="135" border="0" hspace="0" alt="Promotional Image" src="/Home/ads/webtv3.gif">
|
||||
</div>
|
||||
<div style="position:absolute; left:5px; top:0px"><a id="PromoImageLinkID" href="">
|
||||
<table width="173" height="135"><tr><td></td></tr></table></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="timerRotatorDiv" class="personalPanelDiv" onclick="ClickRotator()">
|
||||
<div>
|
||||
<div style="top:0px; left:0px; width:176px; height:105px;" xmlns:msntvuxp="msntvuxp.microsoft.com">
|
||||
<div class="PNGImage" style="width:176px;height:105px;src:/images/Home/HomeRotatorBGWeather.png;"></div>
|
||||
</div>
|
||||
<div style="position:absolute; top:0px; left:0px; width:178px; height:107px;" xmlns:msntvuxp="msntvuxp.microsoft.com">
|
||||
<table class="wthrTbl" border="0" cellpadding="1" cellspacing="0">
|
||||
<tr>
|
||||
<td height="4" width="4" rowspan="4"><img src="images/Shared/s.gif" height="4" width="4"></td>
|
||||
<td height="4" width="45"><img src="images/Shared/s.gif" height="4" width="45"></td>
|
||||
<td height="4" width="10"><img src="images/Shared/s.gif" height="4" width="10"></td>
|
||||
<td height="4" width="65"><img src="images/Shared/s.gif" height="4" width="65"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="CityCellID" class="wthrCityCell" colspan="3" valign="top">
|
||||
<span class="wthrCityText">${WeatherCity}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="TRCID" class="wthrTempCond">
|
||||
<table>
|
||||
<tr>
|
||||
<td id="TemperatureCellID" class="wthrTempCell">
|
||||
<span class="wthrTempTxt">${WeatherTemp}°F</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="ConditionCellID" class="wthrCondCell">
|
||||
<span class="wthrCondTxt">${WeatherDescription}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td id="PaddingID" width="10"><img src="images/Shared/s.gif" height="1" width="10"></td>
|
||||
<td id="ConditionIconID" class="wthrCondIcon">
|
||||
<img src="${WeatherIcon}" alt="Weather icon" style="width:65px;height:61px;">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="ProviderID" class="wthrProvider" colspan="3">
|
||||
Open-Meteo
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<script xmlns:msntvuxp="msntvuxp.microsoft.com">
|
||||
function clickPageRotatePanel() {
|
||||
location.href = "/Pages/weather/yourcity";
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
InitRotator(timerRotatorDiv, 5000, new Array("/home/MoneyModule.aspx","/Pages/weather/WeatherModule"));
|
||||
</script>
|
||||
|
||||
<div ID="clockID" class="clockDiv">
|
||||
</div>
|
||||
<script>clockID.innerHTML = formClockLink();</script>
|
||||
|
||||
<div class="newsHdlnDiv">
|
||||
<div class="newsHdlnTitleDiv"><span class="newsHdlnTitleText">Today on TV2</span></div>
|
||||
<table style="top:0px;left:0px;width:365px;height:78px;">
|
||||
<tr><td><a class="newsHdlnLink" id="newsHdlnLinkID1" href="${NewsLink1}">${NewsTitle1}</a></td></tr>
|
||||
<tr><td><a class="newsHdlnLink" id="newsHdlnLinkID2" href="${NewsLink2}">${NewsTitle2}</a></td></tr>
|
||||
<tr><td><a class="newsHdlnLink" id="newsHdlnLinkID3" href="${NewsLink3}">${NewsTitle3}</a></td></tr>
|
||||
</table>
|
||||
<div class="moreNewsDiv">
|
||||
<table><tr>
|
||||
<td><img src="msntv:/Shared/images/BulletCustom.gif" height="14" width="7"></td>
|
||||
<td><img src="images/Shared/s.gif" height="1" width="4"></td>
|
||||
<td style="height:37px"><a id="moreNewsLinkID" class="moreNewsLink" href="../pages/TopStories">More MSN news</a></td>
|
||||
</tr></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="promoPanelDiv">
|
||||
<div style="position:absolute; width:355px; height:70px;">
|
||||
<table style="width:365px;">
|
||||
<td class="promoHdlnTitle" style="color:#1D704C">Using MSN TV</td>
|
||||
<tr>
|
||||
<td class="promoHdlnCell"><a class="promoHdlnLink" id="promoHdlnLinkID1" href="http://msntv.msn.com/pages/usingmsntv/tippage.aspx?id=set15">Tip: Turn on audible dialing </a></td></tr><tr>
|
||||
<td class="promoHdlnCell"><a class="promoHdlnLink" id="promoHdlnLinkID2" href="http://msntv.msn.com/pages/UsingMSNTV/Article.aspx?id=feature3">Get better printing results</a></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div style="position:absolute; left:161px; top:74px; width:200px;">
|
||||
<table class="MoreUsingLinkTable"><tr>
|
||||
<td><img src="msntv:/Shared/Images/BulletCustom.gif" height="14" width="7"></td>
|
||||
<td><img src="/Images/Shared/s.gif" height="1" width="4"></td>
|
||||
<td>
|
||||
<a id="MoreUsingLinkID" class="MoreNewsLink" href="http://headwaiter.trusted.msntv.msn.com/Pages/UsingMSNTV/Main">Go to Using MSN TV</a>
|
||||
</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="searchID" class="searchDiv">
|
||||
<div class="searchCenterDiv">
|
||||
<script>
|
||||
function doSearch(country){
|
||||
if (searchFormID.searchFieldID.value == "")
|
||||
{
|
||||
window.location = window.external.SafeGetServiceURL('search::search') + "?FORM=WEBTV&cfg=MSTVXML&v=1&c="+country+"&x=26&y=14";
|
||||
}
|
||||
else
|
||||
{
|
||||
window.location = window.external.SafeGetServiceURL('search::search') + "?FORM=WEBTV&cfg=MSTVXML&v=1&c="+country+"&x=26&y=14&q=" + escape(searchFormID.searchFieldID.value);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<div style="position:absolute; z-index:1; left:0; top:0px; width:100%; height:2px; background-color:#0c7faa;">
|
||||
<table style="width:100%; height:2px;"><tr><td height="2"></td></tr></table>
|
||||
</div>
|
||||
<table class="searchTbl">
|
||||
<form id="searchFormID" action="javascript:doSearch('US')">
|
||||
<tr>
|
||||
<td width="10"></td>
|
||||
<td><a class="searchLink" href="javascript:doSearch('US');">Search</a><span class="searchLabelText"> or type www</span></td>
|
||||
<td></td>
|
||||
<td><span class="searchFieldText"><input id="searchFieldID" name="searchFieldName" class="searchField" type="text" size="28"></span></td>
|
||||
<td></td>
|
||||
<td valign="center"><msntv:custombutton id="GoButtonID" onClick="doSearch('US');" label="Go" /></td>
|
||||
</tr></form></table>
|
||||
<div style="position:absolute; left:0; top:33px; width:100%; height:2px; background-color:#1c4373;">
|
||||
<table style="width:100%; height:2px;"><tr><td height="2"></td></tr></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="iconNavBarID" class="iconNavBar">
|
||||
<table class="iconNavBarMasterTbl">
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<table class="iconNavBarTbl">
|
||||
<tr>
|
||||
<td class="iconNavBarTblFrameCell">
|
||||
<table class="ApolloIcons" xmlns:msntv="http://tv.msn.com">
|
||||
<tr height="70">
|
||||
<td>
|
||||
<msntv:loopingDIV id="navbar" hasInitialFocus="true" divWidthPX="554" onLoopingDivReady="handleLoopingDivReady()" />
|
||||
</td>
|
||||
</tr>
|
||||
<script>
|
||||
var nIcons;
|
||||
var ImgURL = new Array();
|
||||
var ImgWidth = new Array();
|
||||
var ImgOverURL = new Array();
|
||||
var IconURL = new Array();
|
||||
|
||||
function goToFavorites() {
|
||||
window.open(" ", "favoritespanel", "msntv:panel");
|
||||
}
|
||||
function goToMessenger() {
|
||||
if (window.external.SafeGetServiceURL('messenger::root') != null && window.external.SafeGetServiceURL('messenger::root') != "") window.open(" ", "impanel", "msntv:panel");
|
||||
else window.location = "msntv:/OLTK/IMBlock.html";
|
||||
}
|
||||
function goToMail() {
|
||||
if (window.external.SafeGetServiceURL('mail::listmail') != null && window.external.SafeGetServiceURL('mail::listmail') != "") window.location = window.external.SafeGetServiceURL('mail::listmail');
|
||||
else window.location = "msntv:/OLTK/EmailBlock.html";
|
||||
}
|
||||
function goToChat() {
|
||||
if (window.external.SafeGetServiceURL('chat::home') != null && window.external.SafeGetServiceURL('chat::home') != "") window.location = window.external.SafeGetServiceURL('chat::home');
|
||||
else window.location = "msntv:/OLTK/chatBlock.html";
|
||||
}
|
||||
function goToSearch() { window.location = window.external.SafeGetServiceURL('search::main'); }
|
||||
function goToMaps() { window.location = window.external.SafeGetServiceURL('maps::main'); }
|
||||
function goToMusicHome() { window.location = window.external.SafeGetServiceURL('Music::Home'); }
|
||||
function goToVideoHome() { window.location = window.external.SafeGetServiceURL('Video::Home'); }
|
||||
function goToNetwork() { window.location = window.external.SafeGetServiceURL('Settings::HomeNetwork'); }
|
||||
function goToAccount() { window.location = window.external.SafeGetServiceURL('UAM::UAMbase'); }
|
||||
function goToSettings() { window.location = window.external.SafeGetServiceURL('settings::mainindex'); }
|
||||
function goToCenter(svcURL) { window.location = svcURL; }
|
||||
function goToPhotosApp() { window.location = window.external.SafeGetServiceURL('Photos'); }
|
||||
function goToPhotosHome() { window.location = window.external.SafeGetServiceURL('Photo::Home'); }
|
||||
|
||||
function initIcons() {
|
||||
var dq = '"';
|
||||
for (index = 0; index < nIcons; index++) {
|
||||
var realIndex = (index + nIcons - 1) % nIcons;
|
||||
var cellHTML = '<span' +
|
||||
' onFocus=' + dq + 'ImgObjs' + realIndex + ".src='" + ImgOverURL[realIndex] + "';" + dq +
|
||||
' onBlur=' + dq + 'ImgObjs' + realIndex + ".src='" + ImgURL[realIndex] + "';" + dq +
|
||||
' onClick=' + dq + IconURL[realIndex] + dq +
|
||||
'><img id=' + dq + 'ImgObjs' + realIndex + dq +
|
||||
" src='" + ImgURL[realIndex] + "' width=" + ImgWidth[realIndex] + ' height=61 border=0></span>';
|
||||
navbar.AddCellHTML(cellHTML, ImgWidth[realIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
ImgURL[0] = "/Images/Home/HomeIconFav.jpg";
|
||||
ImgOverURL[0] = "/Images/Home/HomeIconFavOver.jpg";
|
||||
ImgWidth[0] = 87;
|
||||
IconURL[0] = "javascript:goToFavorites();";
|
||||
|
||||
ImgURL[1] = "/Images/Home/HomeIconMail.jpg";
|
||||
ImgOverURL[1] = "/Images/Home/HomeIconMailOver.jpg";
|
||||
ImgWidth[1] = 70;
|
||||
IconURL[1] = "javascript:goToMail();";
|
||||
|
||||
ImgURL[2] = "/Images/Home/HomeIconMsgr.jpg";
|
||||
ImgOverURL[2] = "/Images/Home/HomeIconMsgrOver.jpg";
|
||||
ImgWidth[2] = 99;
|
||||
IconURL[2] = "javascript:goToMessenger();";
|
||||
|
||||
ImgURL[3] = "/Images/Home/HomeIconMaps.jpg";
|
||||
ImgOverURL[3] = "/Images/Home/HomeIconMapsOver.jpg";
|
||||
ImgWidth[3] = 60;
|
||||
IconURL[3] = "javascript:goToMaps();";
|
||||
|
||||
ImgURL[4] = "/Images/Home/HomeIconPhoto.jpg";
|
||||
ImgOverURL[4] = "/Images/Home/HomeIconPhotoOver.jpg";
|
||||
ImgWidth[4] = 70;
|
||||
IconURL[4] = "javascript:goToPhotosApp();";
|
||||
|
||||
ImgURL[5] = "/Images/Home/HomeIconVideos.jpg";
|
||||
ImgOverURL[5] = "/Images/Home/HomeIconVideosOver.jpg";
|
||||
ImgWidth[5] = 70;
|
||||
IconURL[5] = "javascript:goToVideoHome();";
|
||||
|
||||
ImgURL[6] = "/Images/Home/HomeIconMusic.jpg";
|
||||
ImgOverURL[6] = "/Images/Home/HomeIconMusicOver.jpg";
|
||||
ImgWidth[6] = 66;
|
||||
IconURL[6] = "javascript:goToMusicHome();";
|
||||
|
||||
ImgURL[7] = "/Images/Home/HomeIconDiscuss.jpg";
|
||||
ImgOverURL[7] = "/Images/Home/HomeIconDiscussOver.jpg";
|
||||
ImgWidth[7] = 72;
|
||||
IconURL[7] = "javascript:goToCenter('/Pages/Discuss/Home.aspx');";
|
||||
|
||||
ImgURL[8] = "/Images/Home/HomeIconMSNBC.jpg";
|
||||
ImgOverURL[8] = "/Images/Home/HomeIconMSNBCOver.jpg";
|
||||
ImgWidth[8] = 68;
|
||||
IconURL[8] = "javascript:goToCenter('/Pages/News/TopStories.aspx');";
|
||||
|
||||
ImgURL[9] = "/Images/Home/HomeIconTWC.jpg";
|
||||
ImgOverURL[9] = "/Images/Home/HomeIconTWCOver.jpg";
|
||||
ImgWidth[9] = 81;
|
||||
IconURL[9] = "javascript:goToCenter('/Pages/Weather/MyCity.aspx');";
|
||||
|
||||
ImgURL[10] = "/Images/Home/HomeIconEnt.jpg";
|
||||
ImgOverURL[10] = "/Images/Home/HomeIconEntOver.jpg";
|
||||
ImgWidth[10] = 125;
|
||||
IconURL[10] = "javascript:goToCenter('/Pages/Entertainment/Home.aspx');";
|
||||
|
||||
ImgURL[11] = "/Images/Home/HomeIconTVListings.jpg";
|
||||
ImgOverURL[11] = "/Images/Home/HomeIconTVListingsOver.jpg";
|
||||
ImgWidth[11] = 96;
|
||||
IconURL[11] = "javascript:goToCenter('http://tv.msn.com/tv/guide');";
|
||||
|
||||
ImgURL[12] = "/Images/Home/HomeIconSports.jpg";
|
||||
ImgOverURL[12] = "/Images/Home/HomeIconSportsOver.jpg";
|
||||
ImgWidth[12] = 82;
|
||||
IconURL[12] = "javascript:goToCenter('/Pages/Sports/Main.aspx');";
|
||||
|
||||
ImgURL[13] = "/Images/Home/HomeIconMoney.jpg";
|
||||
ImgOverURL[13] = "/Images/Home/HomeIconMoneyOver.jpg";
|
||||
ImgWidth[13] = 68;
|
||||
IconURL[13] = "javascript:goToCenter('/Pages/Money/Home.aspx');";
|
||||
|
||||
ImgURL[14] = "/Images/Home/HomeIconShopping.jpg";
|
||||
ImgOverURL[14] = "/Images/Home/HomeIconShoppingOver.jpg";
|
||||
ImgWidth[14] = 62;
|
||||
IconURL[14] = "javascript:goToCenter('/Pages/Shopping/Main.aspx');";
|
||||
|
||||
ImgURL[15] = "/Images/Home/HomeIconGames.jpg";
|
||||
ImgOverURL[15] = "/Images/Home/HomeIconGamesOver.jpg";
|
||||
ImgWidth[15] = 70;
|
||||
IconURL[15] = "javascript:goToCenter('/Pages/Games/Home.aspx');";
|
||||
|
||||
ImgURL[16] = "/Images/Home/HomeIconEncarta.jpg";
|
||||
ImgOverURL[16] = "/Images/Home/HomeIconEncartaOver.jpg";
|
||||
ImgWidth[16] = 74;
|
||||
IconURL[16] = "javascript:goToCenter('http://g.msn.com/5TVANDURIL/1505')";
|
||||
|
||||
ImgURL[17] = "/Images/Home/HomeIconChat.jpg";
|
||||
ImgOverURL[17] = "/Images/Home/HomeIconChatOver.jpg";
|
||||
ImgWidth[17] = 55;
|
||||
IconURL[17] = "javascript:goToChat();";
|
||||
|
||||
ImgURL[18] = "/Images/Home/HomeIconUsingMSN.jpg";
|
||||
ImgOverURL[18] = "/Images/Home/HomeIconUsingMSNOver.jpg";
|
||||
ImgWidth[18] = 127;
|
||||
IconURL[18] = "javascript:goToCenter('/Pages/UsingMSNTV/Main');";
|
||||
|
||||
ImgURL[19] = "/Images/Home/HomeIconTTT.jpg";
|
||||
ImgOverURL[19] = "/Images/Home/HomeIconTTTOver.jpg";
|
||||
ImgWidth[19] = 116;
|
||||
IconURL[19] = "javascript:goToCenter('/Pages/UsingMSNTV/ThingstoTry');";
|
||||
|
||||
ImgURL[20] = "/Images/Home/HomeIconSearch.jpg";
|
||||
ImgOverURL[20] = "/Images/Home/HomeIconSearchOver.jpg";
|
||||
ImgWidth[20] = 84;
|
||||
IconURL[20] = "javascript:goToSearch();";
|
||||
|
||||
ImgObjs = new Array();
|
||||
ImgOverObjs = new Array();
|
||||
nIcons = ImgURL.length;
|
||||
ImgOverObjs[0] = new Image();
|
||||
ImgOverObjs[0].src = ImgOverURL[0];
|
||||
for (var i = 0; i < nIcons; i++) {
|
||||
ImgObjs[i] = new Image();
|
||||
ImgObjs[i].src = ImgURL[i];
|
||||
}
|
||||
for (var i = 1; i < nIcons; i++) {
|
||||
ImgOverObjs[i] = new Image();
|
||||
ImgOverObjs[i].src = ImgOverURL[i];
|
||||
}
|
||||
initIcons();
|
||||
</script>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function callCGif()
|
||||
{
|
||||
var i = new Image();
|
||||
i.src = "http://c.msn.com/c.gif?DI=1455&PI=68206&PS=45577&TP=http://msntv.msn.com/HomePage.htm&RF=";
|
||||
}
|
||||
window.attachEvent("onload", callCGif);
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
</body></html>`;
|
||||
@@ -0,0 +1,629 @@
|
||||
@page "/Pages/Home/Home.aspx"
|
||||
@using MSNTV2MainServer.Components.Layout
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@using Microsoft.AspNetCore.Components
|
||||
@using MSNTV2MainServer.Components.APIs
|
||||
@inject IHttpContextAccessor httpContextAccessor
|
||||
|
||||
@layout EmptyLayout
|
||||
|
||||
@if (IsTV2)
|
||||
{
|
||||
|
||||
MarkupString htmlContent = new MarkupString($@"
|
||||
<html xmlns:msntv>
|
||||
<?import namespace=""msntv"" implementation=""Shared/Anduril/HTC/en-us/TruncatedHtml.htc""?>
|
||||
|
||||
<head><title>Home</title>
|
||||
<?import namespace=""msntv"" implementation=""HTC/Shared/CustomButton.htc""?>
|
||||
<?import namespace=""msntv"" implementation=""/Pages/Home/Shared/BaseClient/HTCTransforms/en-us/LoopingDIV.htc""?>
|
||||
|
||||
<script src=""/Include/2.0.261.900/localhost-1700/Shared/BaseClient/JsTransforms/en-us/PaneHelp.js"" language=""javascript"" defer=""true""></script>
|
||||
<link href=""/Include/2.0.261.778/localhost-1700/Home/Anduril/CssTransforms/en-us/Home.css"" type=""text/css"" rel=""StyleSheet"">
|
||||
<script src=""/Include/2.0.261.778/localhost-1700/Home/Anduril/JsTransforms/en-us/Home.js"" language=""javascript""></script>
|
||||
|
||||
<script>
|
||||
var forceReload = false;
|
||||
var l = 'd:' + new Date().valueOf() + '|';
|
||||
function setCookie(name, value) {{
|
||||
{{
|
||||
var now = new Date();
|
||||
var expires = new Date(now.getFullYear() + 1, now.getMonth(), now.getDate());
|
||||
document.cookie = escape(name) + '=' + escape(value) + ';expires=' + expires.toGMTString() + ';path=/';
|
||||
}}
|
||||
}}
|
||||
function getCookie(name) {{
|
||||
{{
|
||||
var str = document.cookie;
|
||||
var arr = str.split('; ');
|
||||
for (var i = arr.length - 1; i >= 0; i--) {{
|
||||
{{
|
||||
var c = arr[i].split('=');
|
||||
if (c.length != 2)
|
||||
continue;
|
||||
if (unescape(c[0]) == name)
|
||||
return unescape(c[1]);
|
||||
}}
|
||||
}}
|
||||
return null;
|
||||
}}
|
||||
}}
|
||||
function syncCookie(cookieName, propValue) {{
|
||||
{{
|
||||
var c = getCookie(cookieName);
|
||||
l += 'g:' + cookieName + ':' + c + '|';
|
||||
if (c != propValue) {{
|
||||
{{
|
||||
setCookie(cookieName, propValue);
|
||||
l += 's:' + cookieName + ':' + propValue + '|';
|
||||
var check = getCookie(cookieName);
|
||||
if (check == propValue)
|
||||
forceReload = true;
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
var d = new Date();
|
||||
var utcOffset = d.getTimezoneOffset();
|
||||
syncCookie('UserUtcOffset', utcOffset);
|
||||
var connSpeed;
|
||||
try {{ {{ connSpeed = window.external.ClientCaps.connectionType; }} }}
|
||||
catch (e) {{
|
||||
{{
|
||||
connSpeed = ""undetected"";
|
||||
}}
|
||||
}}
|
||||
syncCookie('UserConnectionSpeed', connSpeed);
|
||||
try {{
|
||||
{{
|
||||
top.log(l);
|
||||
}}
|
||||
}}
|
||||
catch (e) {{
|
||||
{{
|
||||
}}
|
||||
}}
|
||||
if (forceReload)
|
||||
location.replace(location.href);
|
||||
</script></head>
|
||||
|
||||
<body>
|
||||
|
||||
<body onload=""initPage();"" scroll=""no"" tabindex=""-1"">
|
||||
|
||||
<div id=""focdiv"" style=""position:absolute;top:314px;left:27px;width:70px;height:70px;"" onclick=""goToMail();"">
|
||||
|
||||
</div>
|
||||
<script>
|
||||
document.all[""focdiv""].focus();
|
||||
|
||||
// when looping div is ready, you can hide the invisible rectangle used for holding Mail's
|
||||
function handleLoopingDivReady()
|
||||
{{
|
||||
document.all[""focdiv""].style.display = ""none"";
|
||||
}}
|
||||
</script>
|
||||
|
||||
|
||||
<div class=""topdiv"">
|
||||
|
||||
|
||||
<div class=""textMenu"">
|
||||
<script xmlns:msntvuxp=""msntvuxp.microsoft.com"">
|
||||
function goToService(serviceName) {{window.location = window.external.SafeGetServiceURL(serviceName);}}
|
||||
function goToCenter(URL) {{window.location = URL;}}
|
||||
</script>
|
||||
|
||||
<div style=""position:absolute; left:0px; top:0px"" xmlns:msntvuxp=""msntvuxp.microsoft.com"">
|
||||
<table border=""0"" class=""TextMenuTbl"">
|
||||
<tr height=""34"" style=""background-color: transparent;"">
|
||||
<td class=""leftGradientTD""></td><td class=""rightGradientTD"">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div style=""position:absolute; left:0px; top:0px"" xmlns:msntvuxp=""msntvuxp.microsoft.com"">
|
||||
<table border=""0"" class=""TextMenuTbl"">
|
||||
<tr>
|
||||
<td style=""background-color: transparent;"" width=""8"">
|
||||
<img height=""1"" src=""/Images/Shared/s.gif"" width=""8"">
|
||||
</td>
|
||||
<td style=""background-color: transparent;"" align=""left"" width=""162"">
|
||||
<a class=""TextMenuLink"" href=""javascript:goToCenter('/Pages/UsingMSNTV/Main');"" id=""UsingMSNTVLinkID"" onblur=""umtvHasFocus=false"">Using MSN TV</a>
|
||||
</td>
|
||||
|
||||
<div>
|
||||
<span style=""position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;"">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<td style=""background-color: transparent;"" align=""left"" width=""115"">
|
||||
<a class=""TextMenuLink"" href=""javascript:void(window.open(' ', 'signout', 'msntv:panel'));"" id=""SignoutLinkID"">Sign Out</a>
|
||||
</td>
|
||||
|
||||
<div>
|
||||
<span style=""position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;""></span>
|
||||
</div>
|
||||
<td style=""background-color: transparent;"" align=""left"" width=""106"">
|
||||
<a class=""TextMenuLink"" href=""javascript:goToService('UAM::UAMbase');"" id=""AccountLinkID"">Account</a>
|
||||
</td>
|
||||
<div>
|
||||
<span style=""position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;"">
|
||||
</span>
|
||||
</div>
|
||||
<td style=""background-color: transparent;"" align=""left"" width=""109"">
|
||||
<a class=""TextMenuLink"" href=""javascript:goToService('settings::mainindex');"" id=""SettingsLinkID"">Settings</a>
|
||||
</td>
|
||||
<div><span style=""position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;"">
|
||||
</span>
|
||||
</div>
|
||||
<td style=""background-color: transparent;"" align=""left"" width=""78"">
|
||||
<a href='javascript:CallPaneHelp(PH_TOC);' id=""HelpLinkID"">
|
||||
|
||||
<table><tr>
|
||||
<td valign=""middle"" class=""TextMenuLinkSimulation"">Help</td>
|
||||
<td valign=""middle"" width=""30"" height=""20"">
|
||||
<span id=""helpIcon"" style='src:url(msntv:/Shared/Images/Icon_Help_RelatedLink.png);'></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</a>
|
||||
</td>
|
||||
<div>
|
||||
<span style=""position:absolute;left:0;top:35px;width:100%;height:2px;background-color:#8fc3d6;"">
|
||||
</span>
|
||||
</div>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class=""infoPaneDiv"">
|
||||
|
||||
|
||||
<div class=""promoImgDiv"">
|
||||
<div style=""position:absolute; left:0px; top:0px"">
|
||||
<img id=""PromoImageID"" width=""178"" height=""135"" border=""0"" hspace=""0"" alt=""Promotional Image"" src=""/Pages/Home/ads/webtv3.gif"">
|
||||
</div>
|
||||
<div style=""position:absolute; left:5px; top:0px""><a id=""PromoImageLinkID"" href="""">
|
||||
<table width=""173"" height=""135""><tr><td></td></tr></table></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id=""timerRotatorDiv"" class=""personalPanelDiv"" onclick=""ClickRotator()"">
|
||||
<div>
|
||||
<div style=""top:0px; left:0px; width:176px; height:105px;"" xmlns:msntvuxp=""msntvuxp.microsoft.com"">
|
||||
<div class=""PNGImage"" style=""width:176px;height:105px;src:/images/Home/HomeRotatorBGWeather.png;""></div>
|
||||
</div>
|
||||
<div style=""position:absolute; top:0px; left:0px; width:178px; height:107px;"" xmlns:msntvuxp=""msntvuxp.microsoft.com"">
|
||||
<table class=""wthrTbl"" border=""0"" cellpadding=""1"" cellspacing=""0"">
|
||||
<tr>
|
||||
<td height=""4"" width=""4"" rowspan=""4""><img src=""images/Shared/s.gif"" height=""4"" width=""4""></td>
|
||||
<td height=""4"" width=""45""><img src=""images/Shared/s.gif"" height=""4"" width=""45""></td>
|
||||
<td height=""4"" width=""10""><img src=""images/Shared/s.gif"" height=""4"" width=""10""></td>
|
||||
<td height=""4"" width=""65""><img src=""images/Shared/s.gif"" height=""4"" width=""65""></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id=""CityCellID"" class=""wthrCityCell"" colspan=""3"" valign=""top"">
|
||||
<span class=""wthrCityText"">{@Weather.City}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id=""TRCID"" class=""wthrTempCond"">
|
||||
<table>
|
||||
<tr>
|
||||
<td id=""TemperatureCellID"" class=""wthrTempCell"">
|
||||
<span class=""wthrTempTxt"">{@Weather.Temp}°F</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id=""ConditionCellID"" class=""wthrCondCell"">
|
||||
<span class=""wthrCondTxt"">{Weather?.Description}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td id=""PaddingID"" width=""10""><img src=""images/Shared/s.gif"" height=""1"" width=""10""></td>
|
||||
<td id=""ConditionIconID"" class=""wthrCondIcon"">
|
||||
<img src=""{@Weather?.Icon}"" alt=""Weather icon"" style=""width:65px;height:61px;"">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id=""ProviderID"" class=""wthrProvider"" colspan=""3"">
|
||||
Open-Meteo
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<script xmlns:msntvuxp=""msntvuxp.microsoft.com"">
|
||||
function clickPageRotatePanel() {{
|
||||
location.href = ""/Pages/weather/yourcity"";
|
||||
}}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
InitRotator(timerRotatorDiv, 5000, new Array(""/home/MoneyModule.aspx"",""/Pages/weather/WeatherModule""));
|
||||
</script>
|
||||
|
||||
|
||||
<div ID=""clockID"" class=""clockDiv"">
|
||||
</div>
|
||||
<script>clockID.innerHTML = formClockLink();</script>
|
||||
|
||||
|
||||
<div class=""newsHdlnDiv"">
|
||||
<div class=""newsHdlnTitleDiv""><span class=""newsHdlnTitleText"">Today on TV2</span></div><table style=""top:0px;left:0px;width:365px;height:78px;""><tr><td><a class=""newsHdlnLink"" id=""newsHdlnLinkID1"" href=""{@NewsLink1}"">{NewsTitle1}</a></td></tr><tr><td><a class=""newsHdlnLink"" id=""newsHdlnLinkID2"" href=""{@NewsLink2}"">{NewsTitle2}</a></td></tr><tr><td><a class=""newsHdlnLink"" id=""newsHdlnLinkID3"" href=""{@NewsLink3}"">{NewsTitle3}</a></td></tr></table></td></tr></table><div class=""moreNewsDiv""><table><tr><td><img src=""msntv:/Shared/images/BulletCustom.gif"" height=""14"" width=""7""></td><td><img src=""images/Shared/s.gif"" height=""1"" width=""4""></td><td style=""height:37px""><a id=""moreNewsLinkID"" class=""moreNewsLink"" href=""../pages/TopStories"">More MSN news</a></td></tr></table></div>
|
||||
</div>
|
||||
|
||||
<div class=""promoPanelDiv"">
|
||||
<div style=""position:absolute; width:355px; height:70px;"">
|
||||
|
||||
<table style=""width:365px;""><td class=""promoHdlnTitle"" style=""color:#1D704C"">Using MSN TV</td><tr>
|
||||
<td class=""promoHdlnCell""><a class=""promoHdlnLink"" id=""promoHdlnLinkID1"" href=""http://msntv.msn.com/pages/usingmsntv/tippage.aspx?id=set15"">Tip: Turn on audible dialing </a></td></tr><tr>
|
||||
<td class=""promoHdlnCell""><a class=""promoHdlnLink"" id=""promoHdlnLinkID2"" href=""http://msntv.msn.com/pages/UsingMSNTV/Article.aspx?id=feature3"">Get better printing results</a></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div style=""position:absolute; left:161px; top:74px; width:200px;"">
|
||||
<table class=""MoreUsingLinkTable""><tr><td><img src=""msntv:/Shared/Images/BulletCustom.gif"" height=""14"" width=""7""></td><td><img src=""/Images/Shared/s.gif"" height=""1"" width=""4""></td><td>
|
||||
<a id=""MoreUsingLinkID"" class=""MoreNewsLink"" href=""http://headwaiter.trusted.msntv.msn.com/Pages/UsingMSNTV/Main"">Go to Using MSN TV</a>
|
||||
</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id=""searchID"" class=""searchDiv"">
|
||||
|
||||
<div class=""searchCenterDiv"">
|
||||
<script>
|
||||
function doSearch(country){{
|
||||
if (searchFormID.searchFieldID.value == """")
|
||||
{{
|
||||
window.location = window.external.SafeGetServiceURL('search::search'); + ""?FORM=WEBTV&cfg=MSTVXML&v=1&c=""+country+""&x=26&y=14"";
|
||||
}}
|
||||
else
|
||||
{{
|
||||
window.location = window.external.SafeGetServiceURL('search::search') + ""?FORM=WEBTV&cfg=MSTVXML&v=1&c=""+country+""&x=26&y=14&q="" + escape(searchFormID.searchFieldID.value);
|
||||
}}
|
||||
}}
|
||||
</script>
|
||||
|
||||
<div style=""position:absolute; z-index:1; left:0; top:0px; width:100%; height:2px; background-color:#0c7faa;"">
|
||||
<table style="" width:100%; height:2px;"">
|
||||
<tr>
|
||||
<td height=""2"">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<table class=""searchTbl"">
|
||||
<form id=""searchFormID"" action=""javascript:doSearch('US')"">
|
||||
<tr>
|
||||
<td width=""10"">
|
||||
</td><td>
|
||||
<a class=""searchLink"" href=""
|
||||
javascript:doSearch('US');
|
||||
"">Search</a><span class=""searchLabelText""> or type www</span>
|
||||
</td><td></td><td><span class=""searchFieldText""><input id=""searchFieldID"" name=""searchFieldName"" class=""searchField"" type=""text"" size=""28""></span></td><td></td>
|
||||
<td valign=""center""><msntv:custombutton id=""GoButtonID"" onClick=""doSearch('US');"" label=""Go"" /></td></tr></form></table><div style=""position:absolute; left:0; top:33px; width:100%; height:2px; background-color:#1c4373;""><table style="" width:100%; height:2px;""><tr><td height=""2""></td></tr></table></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id=""iconNavBarID"" class=""iconNavBar"">
|
||||
<table class=""iconNavBarMasterTbl"">
|
||||
<tr>
|
||||
<td align=""center"" valign=""middle"">
|
||||
<table class=""iconNavBarTbl"">
|
||||
<tr>
|
||||
<td class=""iconNavBarTblFrameCell"">
|
||||
<table class=""ApolloIcons"" xmlns:msntv=""http://tv.msn.com"">
|
||||
<tr height=""70"">
|
||||
<td>
|
||||
<msntv:loopingDIV id=""navbar"" hasInitialFocus=""true"" divWidthPX=""554"" onLoopingDivReady=""handleLoopingDivReady()"" />
|
||||
</td>
|
||||
</tr>
|
||||
<script>
|
||||
var nIcons;
|
||||
var ImgURL = new Array();
|
||||
var ImgWidth = new Array();
|
||||
var ImgOverURL = new Array();
|
||||
var URL = new Array();
|
||||
|
||||
function goToFavorites() {{
|
||||
window.open("" "", ""favoritespanel"", ""msntv:panel"");
|
||||
}}
|
||||
|
||||
function goToMessenger() {{
|
||||
if (window.external.SafeGetServiceURL('messenger::root') != null && window.external.SafeGetServiceURL('messenger::root') != """") window.open("" "", ""impanel"", ""msntv:panel"");
|
||||
else
|
||||
window.location = ""msntv:/OLTK/IMBlock.html"";
|
||||
}}
|
||||
|
||||
function goToMail() {{
|
||||
if (window.external.SafeGetServiceURL('mail::listmail') != null && window.external.SafeGetServiceURL('mail::listmail') != """") window.location = window.external.SafeGetServiceURL('mail::listmail');
|
||||
else
|
||||
window.location = ""msntv:/OLTK/EmailBlock.html"";
|
||||
}}
|
||||
|
||||
function goToChat() {{
|
||||
if (window.external.SafeGetServiceURL('chat::home') != null && window.external.SafeGetServiceURL('chat::home') != """") window.location = window.external.SafeGetServiceURL('chat::home');
|
||||
else
|
||||
window.location = ""msntv:/OLTK/chatBlock.html"";
|
||||
}}
|
||||
|
||||
function goToSearch() {{
|
||||
window.location = window.external.SafeGetServiceURL('search::main');
|
||||
}}
|
||||
|
||||
function goToMaps() {{
|
||||
window.location = window.external.SafeGetServiceURL('maps::main');
|
||||
}}
|
||||
|
||||
function goToMusicHome() {{
|
||||
window.location = window.external.SafeGetServiceURL('Music::Home');
|
||||
}}
|
||||
|
||||
function goToVideoHome() {{
|
||||
window.location = window.external.SafeGetServiceURL('Video::Home');
|
||||
}}
|
||||
|
||||
function goToNetwork() {{
|
||||
window.location = window.external.SafeGetServiceURL('Settings::HomeNetwork');
|
||||
}}
|
||||
|
||||
function goToAccount() {{
|
||||
window.location = window.external.SafeGetServiceURL('UAM::UAMbase');
|
||||
}}
|
||||
|
||||
function goToSettings() {{
|
||||
window.location = window.external.SafeGetServiceURL('settings::mainindex');
|
||||
}}
|
||||
|
||||
function goToCenter(URL) {{
|
||||
window.location = URL;
|
||||
}}
|
||||
|
||||
function goToPhotosApp() {{
|
||||
window.location = window.external.SafeGetServiceURL('Photos');
|
||||
}}
|
||||
|
||||
function goToPhotosHome() {{
|
||||
window.location = window.external.SafeGetServiceURL('Photo::Home');
|
||||
}}
|
||||
|
||||
function initIcons() {{
|
||||
for (index = 0; index < nIcons; index++) {{
|
||||
var realIndex = (index + nIcons - 1) % nIcons;
|
||||
var cellHTML = ""<span"" + "" onFocus=\""ImgObjs"" + realIndex + "".src='"" + ImgOverURL[realIndex] + ""'\"""" + "" onBlur=\""ImgObjs"" + realIndex + "".src='"" + ImgURL[realIndex] + ""'\"""";
|
||||
cellHTML += "" onClick=\"""" + URL[realIndex] + ""\"""";
|
||||
cellHTML += "">"" + ""<img"" + "" id='ImgObjs"" + realIndex + ""'"" + "" src='"" + ImgURL[realIndex] + ""' width="" + ImgWidth[realIndex] + "" height=61 border=0>"" + ""</span>"";
|
||||
navbar.AddCellHTML(cellHTML, ImgWidth[realIndex]);
|
||||
}}
|
||||
}}
|
||||
|
||||
ImgURL[0] = ""/Images/Home/HomeIconFav.jpg"";
|
||||
ImgOverURL[0] = ""/Images/Home/HomeIconFavOver.jpg"";
|
||||
ImgWidth[0] = 87;
|
||||
URL[0] = ""javascript:goToFavorites();"";
|
||||
|
||||
ImgURL[1] = ""/Images/Home/HomeIconMail.jpg"";
|
||||
ImgOverURL[1] = ""/Images/Home/HomeIconMailOver.jpg"";
|
||||
ImgWidth[1] = 70;
|
||||
URL[1] = ""javascript:goToMail();"";
|
||||
|
||||
ImgURL[2] = ""/Images/Home/HomeIconMsgr.jpg"";
|
||||
ImgOverURL[2] = ""/Images/Home/HomeIconMsgrOver.jpg"";
|
||||
ImgWidth[2] = 99;
|
||||
URL[2] = ""javascript:goToMessenger();"";
|
||||
|
||||
ImgURL[3] = ""/Images/Home/HomeIconMaps.jpg"";
|
||||
ImgOverURL[3] = ""/Images/Home/HomeIconMapsOver.jpg"";
|
||||
ImgWidth[3] = 60;
|
||||
URL[3] = ""javascript:goToMaps();"";
|
||||
|
||||
ImgURL[4] = ""/Images/Home/HomeIconPhoto.jpg"";
|
||||
ImgOverURL[4] = ""/Images/Home/HomeIconPhotoOver.jpg"";
|
||||
ImgWidth[4] = 70;
|
||||
URL[4] = ""javascript:goToPhotosApp();"";
|
||||
|
||||
ImgURL[5] = ""/Images/Home/HomeIconVideos.jpg"";
|
||||
ImgOverURL[5] = ""/Images/Home/HomeIconVideosOver.jpg"";
|
||||
ImgWidth[5] = 70;
|
||||
URL[5] = ""javascript:goToVideoHome();"";
|
||||
|
||||
ImgURL[6] = ""/Images/Home/HomeIconMusic.jpg"";
|
||||
ImgOverURL[6] = ""/Images/Home/HomeIconMusicOver.jpg"";
|
||||
ImgWidth[6] = 66;
|
||||
URL[6] = ""javascript:goToMusicHome();"";
|
||||
|
||||
ImgURL[7] = ""/Images/Home/HomeIconDiscuss.jpg"";
|
||||
ImgOverURL[7] = ""/Images/Home/HomeIconDiscussOver.jpg"";
|
||||
ImgWidth[7] = 72;
|
||||
URL[7] = ""javascript:goToCenter('/Pages/Discuss/Home.aspx');"";
|
||||
|
||||
ImgURL[8] = ""/Images/Home/HomeIconMSNBC.jpg"";
|
||||
ImgOverURL[8] = ""/Images/Home/HomeIconMSNBCOver.jpg"";
|
||||
ImgWidth[8] = 68;
|
||||
URL[8] = ""javascript:goToCenter('/Pages/News/TopStories.aspx');"";
|
||||
|
||||
ImgURL[9] = ""/Images/Home/HomeIconTWC.jpg"";
|
||||
ImgOverURL[9] = ""/Images/Home/HomeIconTWCOver.jpg"";
|
||||
ImgWidth[9] = 81;
|
||||
URL[9] = ""javascript:goToCenter('/Pages/Weather/MyCity.aspx');"";
|
||||
|
||||
ImgURL[10] = ""/Images/Home/HomeIconEnt.jpg"";
|
||||
ImgOverURL[10] = ""/Images/Home/HomeIconEntOver.jpg"";
|
||||
ImgWidth[10] = 125;
|
||||
URL[10] = ""javascript:goToCenter('/Pages/Entertainment/Home.aspx');"";
|
||||
|
||||
ImgURL[11] = ""/Images/Home/HomeIconTVListings.jpg"";
|
||||
ImgOverURL[11] = ""/Images/Home/HomeIconTVListingsOver.jpg"";
|
||||
ImgWidth[11] = 96;
|
||||
URL[11] = ""javascript:goToCenter('http://tv.msn.com/tv/guide');"";
|
||||
|
||||
ImgURL[12] = ""/Images/Home/HomeIconSports.jpg"";
|
||||
ImgOverURL[12] = ""/Images/Home/HomeIconSportsOver.jpg"";
|
||||
ImgWidth[12] = 82;
|
||||
URL[12] = ""javascript:goToCenter('/Pages/Sports/Main.aspx');"";
|
||||
|
||||
ImgURL[13] = ""/Images/Home/HomeIconMoney.jpg"";
|
||||
ImgOverURL[13] = ""/Images/Home/HomeIconMoneyOver.jpg"";
|
||||
ImgWidth[13] = 68;
|
||||
URL[13] = ""javascript:goToCenter('/Pages/Money/Home.aspx');"";
|
||||
|
||||
ImgURL[14] = ""/Images/Home/HomeIconShopping.jpg"";
|
||||
ImgOverURL[14] = ""/Images/Home/HomeIconShoppingOver.jpg"";
|
||||
ImgWidth[14] = 62;
|
||||
URL[14] = ""javascript:goToCenter('/Pages/Shopping/Main.aspx');"";
|
||||
|
||||
ImgURL[15] = ""/Images/Home/HomeIconGames.jpg"";
|
||||
ImgOverURL[15] = ""/Images/Home/HomeIconGamesOver.jpg"";
|
||||
ImgWidth[15] = 70;
|
||||
URL[15] = ""javascript:goToCenter('/Pages/Games/Home.aspx');"";
|
||||
|
||||
ImgURL[16] = ""/Images/Home/HomeIconEncarta.jpg"";
|
||||
ImgOverURL[16] = ""/Images/Home/HomeIconEncartaOver.jpg"";
|
||||
ImgWidth[16] = 74;
|
||||
URL[16] = ""javascript:goToCenter('http://g.msn.com/5TVANDURIL/1505')"";
|
||||
|
||||
ImgURL[17] = ""/Images/Home/HomeIconChat.jpg"";
|
||||
ImgOverURL[17] = ""/Images/Home/HomeIconChatOver.jpg"";
|
||||
ImgWidth[17] = 55;
|
||||
URL[17] = ""javascript:goToChat();"";
|
||||
|
||||
ImgURL[18] = ""/Images/Home/HomeIconUsingMSN.jpg"";
|
||||
ImgOverURL[18] = ""/Images/Home/HomeIconUsingMSNOver.jpg"";
|
||||
ImgWidth[18] = 127;
|
||||
URL[18] = ""javascript:goToCenter('/Pages/UsingMSNTV/Main');"";
|
||||
|
||||
ImgURL[19] = ""/Images/Home/HomeIconTTT.jpg"";
|
||||
ImgOverURL[19] = ""/Images/Home/HomeIconTTTOver.jpg"";
|
||||
ImgWidth[19] = 116;
|
||||
URL[19] = ""javascript:goToCenter('/Pages/UsingMSNTV/ThingstoTry');"";
|
||||
|
||||
ImgURL[20] = ""/Images/Home/HomeIconSearch.jpg"";
|
||||
ImgOverURL[20] = ""/Images/Home/HomeIconSearchOver.jpg"";
|
||||
ImgWidth[20] = 84;
|
||||
URL[20] = ""javascript:goToSearch();"";
|
||||
|
||||
ImgObjs = new Array();
|
||||
ImgOverObjs = new Array();
|
||||
nIcons = ImgURL.length;
|
||||
ImgOverObjs[0] = new Image();
|
||||
ImgOverObjs[0].src = ImgOverURL[0];
|
||||
for (var i = 0; i < nIcons; i++) {{
|
||||
ImgObjs[i] = new Image();
|
||||
ImgObjs[i].src = ImgURL[i];
|
||||
}}
|
||||
for (var i = 1; i < nIcons; i++) {{
|
||||
ImgOverObjs[i] = new Image();
|
||||
ImgOverObjs[i].src = ImgOverURL[i];
|
||||
}}
|
||||
initIcons();
|
||||
</script>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function callCGif()
|
||||
{{
|
||||
var i = new Image();
|
||||
i.src = ""http://c.msn.com/c.gif?DI=1455&PI=68206&PS=45577&TP=http://msntv.msn.com/HomePage.htm&RF="";
|
||||
}}
|
||||
window.attachEvent(""onload"", callCGif);
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</body></html>
|
||||
");
|
||||
|
||||
@((MarkupString)htmlContent)
|
||||
}
|
||||
else
|
||||
{
|
||||
<PageTitle>Home</PageTitle>
|
||||
<h1>Hello, world!</h1>
|
||||
<footer>
|
||||
<div style="position:fixed; left: 0px; bottom: 20px; width: 100vw;">
|
||||
<TV2PCHomeNavBar />
|
||||
</div>
|
||||
<div style="position:fixed; left: 0px; bottom: 0; width: 100vw; height: 40px;">
|
||||
<table cellpadding="0" cellspacing="0" width="100%" height="100%">
|
||||
<tr>
|
||||
<td width="560">
|
||||
<img src="/Images/TV2PC/StatusBarBG.jpg" style="width: 100vw; height: 40px; object-fit: fill;"/>
|
||||
<img src="/Images/TV2PC/Logo_MSNTVStatusBar.png" alt="Overlay Logo" class="overlay-logo" style="position: absolute; right: 0.1vw; bottom: 5px; max-width: 150%; z-index: 1001;" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</footer>
|
||||
}
|
||||
|
||||
@code {
|
||||
string userAgent { get; set; }
|
||||
bool IsTV2 = false;
|
||||
|
||||
// News
|
||||
string NewsLink1 = "http://sg1.trusted.msntv.msn.com/Pages/Tricks/he.mp3";
|
||||
string NewsLink2 = "http://sg1.trusted.msntv.msn.com/Pages/Tricks/pokemon-black-2.mp3";
|
||||
string NewsLink3 = "http://sg1.trusted.msntv.msn.com/Pages/Tricks/he.mp3";
|
||||
string NewsTitle1 = "Ryder Smells";
|
||||
string NewsTitle2 = "Ryder Smells";
|
||||
string NewsTitle3 = "Ryder Smells";
|
||||
|
||||
// Weather mock
|
||||
WeatherData Weather = new WeatherData
|
||||
{
|
||||
City = "San Jose",
|
||||
Temp = "72",
|
||||
Description = "Sunny",
|
||||
Icon = "/Pages/Home/Weather/26.gif"
|
||||
};
|
||||
|
||||
// Date data
|
||||
DateData date = new DateData();
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
var request = httpContextAccessor.HttpContext?.Request;
|
||||
IsTV2 = request != null && SecurityHandler.IsMsnTvClient(request) && SecurityHandler.IsTrustedDomain(request);
|
||||
}
|
||||
|
||||
|
||||
class WeatherData
|
||||
{
|
||||
public string City { get; set; }
|
||||
public string Temp { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Icon { get; set; }
|
||||
}
|
||||
|
||||
class DateData
|
||||
{
|
||||
public string date { get; }
|
||||
|
||||
public DateData()
|
||||
{
|
||||
date = DateTime.Now.ToString("dddd, MMMM d");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
const minisrv_service_file = true;
|
||||
|
||||
headers = `200 OK
|
||||
Content-type: text/html`;
|
||||
|
||||
data = `<html>
|
||||
|
||||
<head>
|
||||
<script>
|
||||
var forceReload = false;
|
||||
var l = 'd:' + new Date().valueOf() + '|';
|
||||
|
||||
function setCookie(name, value) {
|
||||
var now = new Date();
|
||||
var expires = new Date(now.getFullYear() + 1, now.getMonth(), now.getDate());
|
||||
document.cookie = escape(name) + '=' + escape(value) + ';expires=' + expires.toGMTString() + ';path=/';
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
var str = document.cookie;
|
||||
var arr = str.split('; ');
|
||||
for (var i = arr.length - 1; i >= 0; i--) {
|
||||
var c = arr[i].split('=');
|
||||
if (c.length != 2) continue;
|
||||
if (unescape(c[0]) == name) return unescape(c[1]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function syncCookie(cookieName, propValue) {
|
||||
var c = getCookie(cookieName);
|
||||
l += 'g:' + cookieName + ':' + c + '|';
|
||||
if (c != propValue) {
|
||||
setCookie(cookieName, propValue);
|
||||
l += 's:' + cookieName + ':' + propValue + '|';
|
||||
var check = getCookie(cookieName);
|
||||
if (check == propValue) forceReload = true;
|
||||
}
|
||||
}
|
||||
var d = new Date();
|
||||
var utcOffset = d.getTimezoneOffset();
|
||||
syncCookie('UserUtcOffset', utcOffset);
|
||||
var connSpeed;
|
||||
try {
|
||||
connSpeed = window.external.ClientCaps.connectionType;
|
||||
} catch (e) {
|
||||
connSpeed = "undetected";
|
||||
}
|
||||
syncCookie('UserConnectionSpeed', connSpeed);
|
||||
try {
|
||||
top.log(l);
|
||||
} catch (e) {}
|
||||
if (forceReload) location.replace(location.href);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="top:0px; left:0px; width:176px; height:105px;">
|
||||
<div class="PNGImage" style="width:176px;height:105px;src:/Images/Home/HomeRotatorBGStock.png;"></div>
|
||||
</div>
|
||||
<table cellpadding="0" cellspacing="0" class="stocksTbl">
|
||||
<tbody>
|
||||
<tr height="8">
|
||||
<td width="7"></td>
|
||||
<td width="75"></td>
|
||||
<td width="5"></td>
|
||||
<td width="14"></td>
|
||||
<td width="7"></td>
|
||||
<td width="65"></td>
|
||||
<td width="5"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="stocksCell" style="font-weight:bold; overflow:hidden; text-overflow:ellipsis">Dow</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="PNGImage" style="src:/Images/Home/HomeStocksUpArrow.png; width:14px; height:24px"></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class="stocksCell" style="text-align: right;">+54.11</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="stocksRule" colspan="7"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="stocksCell" style="font-weight:bold; overflow:hidden; text-overflow:ellipsis">Nasdaq</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="PNGImage" style="src:/Images/Home/HomeStocksUpArrow.png; width:14px; height:24px"></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class="stocksCell" style="text-align: right;">+6.31</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="stocksRule" colspan="7"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="stocksCell" style="font-weight:bold; overflow:hidden; text-overflow:ellipsis">S&P</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="PNGImage" style="src:/Images/Home/HomeStocksUpArrow.png; width:14px; height:24px"></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class="stocksCell" style="text-align: right;">+3.19</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="stocksRule" colspan="7"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="ProviderID" class="wthrProvider" colspan="6">Source: MSN Money</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--<ROTATOR_FEEDBACK></ROTATOR_FEEDBACK>--><!--<ROTATOR_CLICKTHROUGH>/Pages/Money/MyStocks.aspx</ROTATOR_CLICKTHROUGH>-->
|
||||
<script>
|
||||
function clickPageRotatePanel() {
|
||||
location.href = "/Pages/Money/MyStocks.aspx";
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>`;
|
||||
@@ -0,0 +1,164 @@
|
||||
@page "/Pages/Home/MoneyModule.aspx"
|
||||
@using MSNTV2MainServer.Components.Layout
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@using Microsoft.AspNetCore.Components;
|
||||
@inject IHttpContextAccessor httpContextAccessor
|
||||
|
||||
<!-- Nulled layout as it is defined manually-->
|
||||
@layout EmptyLayout
|
||||
|
||||
|
||||
@if (IsTV2)
|
||||
{
|
||||
MarkupString htmlContent = new MarkupString($@"
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<script>
|
||||
var forceReload = false;
|
||||
var l = 'd:' + new Date().valueOf() + '|';
|
||||
|
||||
function setCookie(name, value) {{
|
||||
var now = new Date();
|
||||
var expires = new Date(now.getFullYear() + 1, now.getMonth(), now.getDate());
|
||||
document.cookie = escape(name) + '=' + escape(value) + ';expires=' + expires.toGMTString() + ';path=/';
|
||||
}}
|
||||
|
||||
function getCookie(name) {{
|
||||
var str = document.cookie;
|
||||
var arr = str.split('; ');
|
||||
for (var i = arr.length - 1; i >= 0; i--) {{
|
||||
var c = arr[i].split('=');
|
||||
if (c.length != 2) continue;
|
||||
if (unescape(c[0]) == name) return unescape(c[1]);
|
||||
}}
|
||||
return null;
|
||||
}}
|
||||
|
||||
function syncCookie(cookieName, propValue) {{
|
||||
var c = getCookie(cookieName);
|
||||
l += 'g:' + cookieName + ':' + c + '|';
|
||||
if (c != propValue) {{
|
||||
setCookie(cookieName, propValue);
|
||||
l += 's:' + cookieName + ':' + propValue + '|';
|
||||
var check = getCookie(cookieName);
|
||||
if (check == propValue) forceReload = true;
|
||||
}}
|
||||
}}
|
||||
var d = new Date();
|
||||
var utcOffset = d.getTimezoneOffset();
|
||||
syncCookie('UserUtcOffset', utcOffset);
|
||||
var connSpeed;
|
||||
try {{
|
||||
connSpeed = window.external.ClientCaps.connectionType;
|
||||
}} catch (e) {{
|
||||
connSpeed = ""undetected"";
|
||||
}}
|
||||
syncCookie('UserConnectionSpeed', connSpeed);
|
||||
try {{
|
||||
top.log(l);
|
||||
}} catch (e) {{}}
|
||||
if (forceReload) location.replace(location.href);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style=""top:0px; left:0px; width:176px; height:105px;"">
|
||||
<div class=""PNGImage"" style=""width:176px;height:105px;src:/Images/Home/HomeRotatorBGStock.png;""></div>
|
||||
</div>
|
||||
<table cellpadding=""0"" cellspacing=""0"" class=""stocksTbl"">
|
||||
<tbody>
|
||||
<tr height=""8"">
|
||||
<td width=""7""></td>
|
||||
<td width=""75""></td>
|
||||
<td width=""5""></td>
|
||||
<td width=""14""></td>
|
||||
<td width=""7""></td>
|
||||
<td width=""65""></td>
|
||||
<td width=""5""></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class=""stocksCell"" style=""font-weight:bold; overflow:hidden; text-overflow:ellipsis"">Dow</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class=""PNGImage"" style=""src:/Images/Home/HomeStocksUpArrow.png; width:14px; height:24px""></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class=""stocksCell"" style=""text-align: right;"">+54.11</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=""stocksRule"" colspan=""7""></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class=""stocksCell"" style=""font-weight:bold; overflow:hidden; text-overflow:ellipsis"">Nasdaq</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class=""PNGImage"" style=""src:/Images/Home/HomeStocksUpArrow.png; width:14px; height:24px""></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class=""stocksCell"" style=""text-align: right;"">+6.31</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=""stocksRule"" colspan=""7""></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class=""stocksCell"" style=""font-weight:bold; overflow:hidden; text-overflow:ellipsis"">S&P</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class=""PNGImage"" style=""src:/Images/Home/HomeStocksUpArrow.png; width:14px; height:24px""></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class=""stocksCell"" style=""text-align: right;"">+3.19</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=""stocksRule"" colspan=""7""></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id=""ProviderID"" class=""wthrProvider"" colspan=""6"">Source: MSN Money</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--<ROTATOR_FEEDBACK></ROTATOR_FEEDBACK>--><!--<ROTATOR_CLICKTHROUGH>/Pages/Money/MyStocks.aspx</ROTATOR_CLICKTHROUGH>-->
|
||||
<script>
|
||||
function clickPageRotatePanel() {{
|
||||
location.href = ""/Pages/Money/MyStocks.aspx"";
|
||||
}}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
");
|
||||
|
||||
@((MarkupString)htmlContent)
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<PageTitle>Home</PageTitle>
|
||||
}
|
||||
|
||||
@code
|
||||
{
|
||||
string userAgent { get; set; }
|
||||
bool IsTV2 = false;
|
||||
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
userAgent = httpContextAccessor.HttpContext.Request.Headers["User-Agent"];
|
||||
|
||||
//Check if the client is an MSNTV2 box. If it is, we should return the TV2 page and not the Blazor based Page.
|
||||
if(userAgent.Contains("MSNTV"))
|
||||
{
|
||||
IsTV2 = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 771 B |
|
After Width: | Height: | Size: 685 B |
|
After Width: | Height: | Size: 806 B |
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 383 B |
|
After Width: | Height: | Size: 403 B |
@@ -0,0 +1,104 @@
|
||||
const minisrv_service_file = true;
|
||||
|
||||
headers = `200 OK
|
||||
Content-type: text/html`;
|
||||
|
||||
data = `<html>
|
||||
|
||||
<head>
|
||||
<script>
|
||||
var forceReload = false;
|
||||
var l = 'd:' + new Date().valueOf() + '|';
|
||||
|
||||
function setCookie(name, value) {
|
||||
var now = new Date();
|
||||
var expires = new Date(now.getFullYear() + 1, now.getMonth(), now.getDate());
|
||||
document.cookie = escape(name) + '=' + escape(value) + ';expires=' + expires.toGMTString() + ';path=/';
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
var str = document.cookie;
|
||||
var arr = str.split('; ');
|
||||
for (var i = arr.length - 1; i >= 0; i--) {
|
||||
var c = arr[i].split('=');
|
||||
if (c.length != 2) continue;
|
||||
if (unescape(c[0]) == name) return unescape(c[1]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function syncCookie(cookieName, propValue) {
|
||||
var c = getCookie(cookieName);
|
||||
l += 'g:' + cookieName + ':' + c + '|';
|
||||
if (c != propValue) {
|
||||
setCookie(cookieName, propValue);
|
||||
l += 's:' + cookieName + ':' + propValue + '|';
|
||||
var check = getCookie(cookieName);
|
||||
if (check == propValue) forceReload = true;
|
||||
}
|
||||
}
|
||||
var d = new Date();
|
||||
var utcOffset = d.getTimezoneOffset();
|
||||
syncCookie('UserUtcOffset', utcOffset);
|
||||
var connSpeed;
|
||||
try {
|
||||
connSpeed = window.external.ClientCaps.connectionType;
|
||||
} catch (e) {
|
||||
connSpeed = "undetected";
|
||||
}
|
||||
syncCookie('UserConnectionSpeed', connSpeed);
|
||||
try {
|
||||
top.log(l);
|
||||
} catch (e) {}
|
||||
if (forceReload) location.replace(location.href);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="top:0px; left:0px; width:176px; height:105px;" xmlns:msntvuxp="msntvuxp.microsoft.com">
|
||||
<div class="PNGImage" style="width:176px;height:105px;src:/Images/Home/HomeRotatorBGWeather.png;"></div>
|
||||
</div>
|
||||
<div style="position:absolute; top:0px; left:0px; width:178px; height:107px;" xmlns:msntvuxp="msntvuxp.microsoft.com">
|
||||
<table class="wthrTbl" border="0" cellpadding="1" cellspacing="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td height="4" width="4" rowspan="4"><img src="/Images/Shared/s.gif" height="4" width="4"></td>
|
||||
<td height="4" width="45"><img src="/Images/Shared/s.gif" height="4" width="45"></td>
|
||||
<td height="4" width="10"><img src="/Images/Shared/s.gif" height="4" width="10"></td>
|
||||
<td height="4" width="65"><img src="/Images/Shared/s.gif" height="4" width="65"></td>
|
||||
<td height="4" width="10" rowspan="4"><img src="/Images/Shared/s.gif" height="4" width="10"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="CityCellID" class="wthrCityCell" colspan="3" valign="top"><span class="wthrCityText">Your City</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="TRCID" class="wthrTempCond">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td id="TemperatureCellID" class="wthrTempCell"><span class="wthrTempTxt">63°/50</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="ConditionCellID" class="wthrCondCell"><span class="wthrCondTxt">Mostly</span><br><span class="wthrCondTxt"> Cloudy</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
<td id="PaddingID" width="10"><img src="/Images/Shared/s.gif" height="1" width="10"></td>
|
||||
<td id="ConditionIconID" class="wthrCondIcon"><span class="PNGImage" style="src:/Images/Shared/Weather/28.png;width:65px;height:61px;"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="ProviderID" class="wthrProvider" colspan="3">The Weather Channel ®</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--<ROTATOR_FEEDBACK></ROTATOR_FEEDBACK>--><!--<ROTATOR_CLICKTHROUGH>/Pages/Weather/YourCity.aspx</ROTATOR_CLICKTHROUGH>-->
|
||||
<script xmlns:msntvuxp="msntvuxp.microsoft.com">
|
||||
function clickPageRotatePanel() {
|
||||
location.href = "/Pages/Weather/YourCity.aspx";
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>`;
|
||||
@@ -0,0 +1,166 @@
|
||||
@page "/Pages/Home/WeatherModule.aspx"
|
||||
@using MSNTV2MainServer.Components.Layout
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@using Microsoft.AspNetCore.Components;
|
||||
@inject IHttpContextAccessor httpContextAccessor
|
||||
|
||||
<!-- Nulled layout as it is defined manually-->
|
||||
@layout EmptyLayout
|
||||
|
||||
|
||||
@if (IsTV2)
|
||||
{
|
||||
|
||||
MarkupString htmlContent = new MarkupString($@"
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<script>
|
||||
var forceReload = false;
|
||||
var l = 'd:' + new Date().valueOf() + '|';
|
||||
|
||||
function setCookie(name, value) {{
|
||||
var now = new Date();
|
||||
var expires = new Date(now.getFullYear() + 1, now.getMonth(), now.getDate());
|
||||
document.cookie = escape(name) + '=' + escape(value) + ';expires=' + expires.toGMTString() + ';path=/';
|
||||
}}
|
||||
|
||||
function getCookie(name) {{
|
||||
var str = document.cookie;
|
||||
var arr = str.split('; ');
|
||||
for (var i = arr.length - 1; i >= 0; i--) {{
|
||||
var c = arr[i].split('=');
|
||||
if (c.length != 2) continue;
|
||||
if (unescape(c[0]) == name) return unescape(c[1]);
|
||||
}}
|
||||
return null;
|
||||
}}
|
||||
|
||||
function syncCookie(cookieName, propValue) {{
|
||||
var c = getCookie(cookieName);
|
||||
l += 'g:' + cookieName + ':' + c + '|';
|
||||
if (c != propValue) {{
|
||||
setCookie(cookieName, propValue);
|
||||
l += 's:' + cookieName + ':' + propValue + '|';
|
||||
var check = getCookie(cookieName);
|
||||
if (check == propValue) forceReload = true;
|
||||
}}
|
||||
}}
|
||||
var d = new Date();
|
||||
var utcOffset = d.getTimezoneOffset();
|
||||
syncCookie('UserUtcOffset', utcOffset);
|
||||
var connSpeed;
|
||||
try {{
|
||||
connSpeed = window.external.ClientCaps.connectionType;
|
||||
}} catch (e) {{
|
||||
connSpeed = ""undetected"";
|
||||
}}
|
||||
syncCookie('UserConnectionSpeed', connSpeed);
|
||||
try {{
|
||||
top.log(l);
|
||||
}} catch (e) {{}}
|
||||
if (forceReload) location.replace(location.href);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style=""top:0px; left:0px; width:176px; height:105px;"" xmlns:msntvuxp=""msntvuxp.microsoft.com"">
|
||||
<div class=""PNGImage"" style=""width:176px;height:105px;src:/Images/Home/HomeRotatorBGWeather.png;""></div>
|
||||
</div>
|
||||
<div style=""position:absolute; top:0px; left:0px; width:178px; height:107px;"" xmlns:msntvuxp=""msntvuxp.microsoft.com"">
|
||||
<table class=""wthrTbl"" border=""0"" cellpadding=""1"" cellspacing=""0"">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td height=""4"" width=""4"" rowspan=""4""><img src=""/Images/Shared/s.gif"" height=""4"" width=""4""></td>
|
||||
<td height=""4"" width=""45""><img src=""/Images/Shared/s.gif"" height=""4"" width=""45""></td>
|
||||
<td height=""4"" width=""10""><img src=""/Images/Shared/s.gif"" height=""4"" width=""10""></td>
|
||||
<td height=""4"" width=""65""><img src=""/Images/Shared/s.gif"" height=""4"" width=""65""></td>
|
||||
<td height=""4"" width=""10"" rowspan=""4""><img src=""/Images/Shared/s.gif"" height=""4"" width=""10""></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id=""CityCellID"" class=""wthrCityCell"" colspan=""3"" valign=""top""><span class=""wthrCityText"">Your City</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id=""TRCID"" class=""wthrTempCond"">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td id=""TemperatureCellID"" class=""wthrTempCell""><span class=""wthrTempTxt"">63°/50</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id=""ConditionCellID"" class=""wthrCondCell""><span class=""wthrCondTxt"">Mostly</span><br><span class=""wthrCondTxt""> Cloudy</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
<td id=""PaddingID"" width=""10""><img src=""/Images/Shared/s.gif"" height=""1"" width=""10""></td>
|
||||
<td id=""ConditionIconID"" class=""wthrCondIcon""><span class=""PNGImage"" style=""src:/Images/Shared/Weather/28.png;width:65px;height:61px;""></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id=""ProviderID"" class=""wthrProvider"" colspan=""3"">The Weather Channel ®</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--<ROTATOR_FEEDBACK></ROTATOR_FEEDBACK>--><!--<ROTATOR_CLICKTHROUGH>/Pages/Weather/YourCity.aspx</ROTATOR_CLICKTHROUGH>-->
|
||||
<script xmlns:msntvuxp=""msntvuxp.microsoft.com"">
|
||||
function clickPageRotatePanel() {{
|
||||
location.href = ""/Pages/Weather/YourCity.aspx"";
|
||||
}}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
");
|
||||
|
||||
@((MarkupString)htmlContent)
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<PageTitle>Home</PageTitle>
|
||||
|
||||
<h1>Hello, world!</h1>
|
||||
<footer>
|
||||
<div style="position:fixed; left: 0px; bottom: 20px; width: 100vw;">
|
||||
|
||||
<TV2PCHomeNavBar />
|
||||
</div>
|
||||
<div style="position:fixed; left: 0px; bottom: 0; width: 100vw; height: 40px;">
|
||||
<table cellpadding="0" cellspacing="0" width="100%" height="100%">
|
||||
<tr>
|
||||
<td width="560">
|
||||
<img src="/Images/TV2PC/StatusBarBG.jpg" style=" width: 100vw; height: 40px; object-fit: fill;"/>
|
||||
<img src="/Images/TV2PC/Logo_MSNTVStatusBar.png" alt="Overlay Logo" class="overlay-logo" style="position: absolute; right: 0.1vw; bottom: 5px; max-width: 150%; z-index: 1001;" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</footer>
|
||||
}
|
||||
|
||||
@code
|
||||
{
|
||||
string userAgent { get; set; }
|
||||
bool IsTV2 = false;
|
||||
|
||||
string NewsLink1 = "https://google.com";
|
||||
string NewsLink2 = "https://yahoo.com";
|
||||
string NewsLink3 = "https://bing.com";
|
||||
string NewsTitle1 = "Google reigns superior over the universe";
|
||||
string NewsTitle2 = "Who even uses Yahoo anymore?";
|
||||
string NewsTitle3 = "Oh god, it's Bing! (Now with extra piss)";
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
userAgent = httpContextAccessor.HttpContext.Request.Headers["User-Agent"];
|
||||
|
||||
//Check if the client is an MSNTV2 box. If it is, we should return the TV2 page and not the Blazor based Page.
|
||||
@if(userAgent.Contains("MSNTV"))
|
||||
{
|
||||
IsTV2 = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 671 B |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 811 B |