Commit c4d05080 authored by 神楽坂玲奈's avatar 神楽坂玲奈

数据库、成就、README

parent 5d71924e
...@@ -4,6 +4,18 @@ ...@@ -4,6 +4,18 @@
毛玉只是开发代号,不作为最终名称,可能会并入mycard 毛玉只是开发代号,不作为最终名称,可能会并入mycard
## 要解决的问题
* 找资源(本体、更新补丁、语言包)繁琐,尤其是过时资源
* 在中国大陆即使想购买正版也很难买到
* 独立游戏作者没有渠道发布游戏
* (需要联机的游戏)跨运营商互访困难、没有公网IP
* 需要手动下载安装vc++运行时、DirectX运行时等依赖项,这个并不是所有人都会的
* 有些游戏甚至要配置一下才能用,例如东方心绮楼需要玩家手动在目录下建立个network_history的文件才能进行联机;要起英文以外的profile名字必须手动改文件;要换头像必须手动改文件
* 存档和个人资料同步(例如非想天则玩家卡组)
* 有些游戏原生不支持某些平台,但是有办法能调教起来,例如东方大多数游戏可以用wine在Linux/OSX下运行
* 有些游戏系统需要依赖网络实现(例如成就),而游戏作者可能并不擅长这个
* 社交、战绩统计
## 功能列表 (发布之前) ## 功能列表 (发布之前)
* 用户登录 * 用户登录
* 聊天 * 聊天
...@@ -80,14 +92,64 @@ ...@@ -80,14 +92,64 @@
二进制文件可以在 http://test2.my-card.in/downloads/maotama/maotama_win32_binaries.7z 下载 二进制文件可以在 http://test2.my-card.in/downloads/maotama/maotama_win32_binaries.7z 下载
## 数据定义
应用
id --> 必填, 标识符,通常是英文简称,由小写字母、数字、下划线组成
category --> 必填, 应用类型
category: game --> 游戏,以及其他不方便归类的可执行程序
category: audio --> 音频,音乐等
category: video --> 视频,动画等
category: graphics --> 静态图片,漫画等
category: book --> FanBook、小说等
category: development --> 开发者相关,通常是运行时依赖项,例如 DirectX
name --> 必填, 应用名称 //TODO: i18n
network --> 如果应用需要反重力场功能,在这里填写网络相关信息
protocol --> 协议,必须为udp
port --> 默认端口
main --> 主程序文件名 //TODO: 跨平台
summary --> 应用介绍
download --> 必填, 下载信息
languages --> 语言的数组,语言是像zh-CN这样的字符串
mods --> 附加模块的数组. mods和dependencies的区别是,mods必须依赖于应用本体而存在,dependencies可以独立存在,可以为多个应用服务
name --> 对于type=language以外必填, 名称 //TODO: i18n
type --> 必填, 模块类型
type: language --> 语言包
type: dlc --> DLC
languages --> type=language时必填,语言的数组
override_main --> 覆盖应用的入口程序
main --> mod自己的入口程序
download --> 必填,下载信息
dependencies --> 相关资源
id --> 必填,id
type --> 必填,依赖类型
type: require --> 必需依赖 例如 DirectX //TODO: 跨平台
type: optional --> 可选依赖 例如 th123 -> th135
achievements --> 收集要素的数组
name --> 收集要素名称,例如 【成就】、【符卡】
type --> 必填,收集要素类型
type:unlock --> 解锁
items --> 必填,具体的收集要素项目的数组
icon --> 必填,图标的url,协议必须是http、https之一
name --> 必填,标题
description --> 介绍
下载信息
url --> 必填,协议必须是http、https、ftp之一
size --> 必填,文件大小,字节数
checksum --> 必填,md5校验码
## API ## API
* XMPP my-card.in * XMPP my-card.in
* XMPP聊天室 conference.my-card.in * XMPP聊天室 conference.my-card.in
* 以下全都为临时,开发用 * 以下全都为临时,开发用
* 用户认证 https://my-card.in/users/me.json?name=用户名&password=密码 * 用户认证 https://my-card.in/users/me.json?name=用户名&password=密码
* 反重力场 ws://122.0.65.69:10800/ * 反重力场 ws://122.0.65.69:10800/
* 资源列表 https://github.com/mycard/maotama/raw/master/apps.json * 应用列表 (本地app目录) apps.json
* 资源下载 http://test2.my-card.in/downloads/maotama/ * 应用元文件 (本地app目录) meta
## 相关技术 ## 相关技术
......
[
{
"id": "th135",
"category": "game",
"name": "东方心绮楼",
"network": {
"protocol": "udp",
"port": 10800
},
"main": "th135.exe",
"summary": "喵喵喵喵喵帕斯 \nnyanpass nyanpass",
"download": {
"url": "http://test2.my-card.in/downloads/maotama/th135_1.33.7z",
"size": 313177031,
"checksum": "ab3c7f4646e080fb88959978865ebf24"
},
"languages": ["ja-JP"],
"mods": [
{
"override_main": "th135c.exe",
"type": "language",
"languages": ["zh-CN"],
"download": {
"url": "http://test2.my-card.in/downloads/maotama/th135_lang_zh-CN_1.33.7z",
"size": 74749190,
"checksum": "49111c67d941e30384251a2026ba67ba"
}
}
]
},
{
"id": "th123",
"category": "game",
"name": "东方非想天则",
"network": {
"protocol": "udp",
"port": 10800
},
"summary": "",
"download": {
"url": "http://test2.my-card.in/downloads/maotama/th123_1.10a.7z",
"size": 250272482,
"checksum": "027a358a7ac014f725ebb8659f1caa6f"
},
"main": "th123.exe",
"languages": ["ja-JP"],
"mods": [
{
"type": "language",
"languages": ["zh-CN"],
"override_main": "th123_beta.exe",
"download": {
"url": "http://test2.my-card.in/downloads/maotama/th123_lang_zh-CN_1.10a.7z",
"size": 7711357,
"checksum": "4e947e2cded2ed21cf691d6ad3bdd04b"
}
}
],
"dependencies": [
{
"id": "th105",
"type": "optional"
}
]
},
{
"id": "th105",
"category": "game",
"name": "东方绯想天",
"network": {
"protocol": "udp",
"port": 10800
},
"summary": "0 0",
"download": {
"url": "http://test2.my-card.in/downloads/maotama/th105_1.06a.7z",
"size": 274941544,
"checksum": "4cd0360e11847ddd7645017769cad73e"
},
"main": "th105.exe",
"languages": ["ja-JP"],
"mods": [
{
"type": "language",
"languages": ["zh-CN"],
"download": {
"url": "http://test2.my-card.in/downloads/maotama/th105_lang_zh-CN_1.06a.7z",
"size": 8809810,
"checksum": "26fb9f83fe957e266377e70fe91aee3b"
}
}
],
"related": [
{
"id": "th105",
"type": "recommended"
}
]
},
{
"id": "leq",
"category": "game",
"name": "萝莉的远征Q:偷菜大战",
"summary": "六一,送大家一个好礼物! \n也是华音的生日!",
"download": {
"url": "http://test2.my-card.in/downloads/maotama/leq.7z",
"size": 2210749,
"checksum": "8550d57175cd1e0a66fae2c406981121"
},
"icon": "meta/leq/icon.png",
"main": "game.exe",
"languages": ["zh-CN"],
"achievements": [
{
"name": "成就",
"type": "unlock",
"items": [
{
"icon": "meta/leq/1.png",
"name": "第一关",
"description": "喵喵喵喵喵帕斯"
},
{
"icon": "meta/leq/2.png",
"name": "第二关",
"description": "喵喵喵喵喵帕斯"
},
{
"icon": "meta/leq/3.png",
"name": "第三关",
"description": "喵喵喵喵喵帕斯"
},
{
"icon": "meta/leq/4.png",
"name": "第四关",
"description": "喵喵喵喵喵帕斯"
},
{
"icon": "meta/leq/5.png",
"name": "第五关",
"description": "喵喵喵喵喵帕斯"
},
{
"icon": "meta/leq/6.png",
"name": "第六关",
"description": "喵喵喵喵喵帕斯"
},
{
"icon": "meta/leq/7.png",
"name": "第七关",
"description": "喵喵喵喵喵帕斯"
},
{
"icon": "meta/leq/8.png",
"name": "第八关",
"description": "Game Over"
}
]
}
]
}
]
\ No newline at end of file
...@@ -107,6 +107,7 @@ ...@@ -107,6 +107,7 @@
<script src="lib/angular/angular.min.js"></script> <script src="lib/angular/angular.min.js"></script>
<script src="lib/angular/angular-route.min.js"></script> <script src="lib/angular/angular-route.min.js"></script>
<script src="lib/angular/angular-sanitize.min.js"></script>
<script src="js/filters.js"></script> <script src="js/filters.js"></script>
<script src="js/services.js"></script> <script src="js/services.js"></script>
<script src="js/directives.js"></script> <script src="js/directives.js"></script>
......
maotama = angular.module 'maotama', [ maotama = angular.module 'maotama', [
'ngRoute', 'ngRoute',
'ngSanitize',
'maotama.filters', 'maotama.filters',
'maotama.services', 'maotama.services',
'maotama.directives', 'maotama.directives',
...@@ -11,6 +12,6 @@ maotama.config ['$routeProvider',($routeProvider)-> ...@@ -11,6 +12,6 @@ maotama.config ['$routeProvider',($routeProvider)->
.when '/apps/:app_id', .when '/apps/:app_id',
templateUrl: 'partials/app_show.html', templateUrl: 'partials/app_show.html',
controller: 'AppsShowController' controller: 'AppsShowController'
.otherwise #.otherwise
redirectTo:'/apps/th123' # redirectTo:'/apps/th123'
] ]
\ No newline at end of file
...@@ -2,15 +2,13 @@ ...@@ -2,15 +2,13 @@
(function() { (function() {
var maotama; var maotama;
maotama = angular.module('maotama', ['ngRoute', 'maotama.filters', 'maotama.services', 'maotama.directives', 'maotama.controllers']); maotama = angular.module('maotama', ['ngRoute', 'ngSanitize', 'maotama.filters', 'maotama.services', 'maotama.directives', 'maotama.controllers']);
maotama.config([ maotama.config([
'$routeProvider', function($routeProvider) { '$routeProvider', function($routeProvider) {
return $routeProvider.when('/apps/:app_id', { return $routeProvider.when('/apps/:app_id', {
templateUrl: 'partials/app_show.html', templateUrl: 'partials/app_show.html',
controller: 'AppsShowController' controller: 'AppsShowController'
}).otherwise({
redirectTo: '/apps/th123'
}); });
} }
]); ]);
......
...@@ -6,5 +6,5 @@ ...@@ -6,5 +6,5 @@
"app.coffee" "app.coffee"
], ],
"names": [], "names": [],
"mappings": ";AAAA;AAAA,MAAA,OAAA;;AAAA,EAAA,OAAA,GAAU,OAAO,CAAC,MAAR,CAAe,SAAf,EAA0B,CAClC,SADkC,EAElC,iBAFkC,EAGlC,kBAHkC,EAIlC,oBAJkC,EAKlC,qBALkC,CAA1B,CAAV,CAAA;;AAAA,EAQA,OAAO,CAAC,MAAR,CAAe;IAAC,gBAAD,EAAkB,SAAC,cAAD,GAAA;aAC/B,cACA,CAAC,IADD,CACM,eADN,EAEI;AAAA,QAAA,WAAA,EAAa,wBAAb;AAAA,QACA,UAAA,EAAY,oBADZ;OAFJ,CAIA,CAAC,SAJD,CAKI;AAAA,QAAA,UAAA,EAAW,aAAX;OALJ,EAD+B;IAAA,CAAlB;GAAf,CARA,CAAA;AAAA" "mappings": ";AAAA;AAAA,MAAA,OAAA;;AAAA,EAAA,OAAA,GAAU,OAAO,CAAC,MAAR,CAAe,SAAf,EAA0B,CAClC,SADkC,EAElC,YAFkC,EAGlC,iBAHkC,EAIlC,kBAJkC,EAKlC,oBALkC,EAMlC,qBANkC,CAA1B,CAAV,CAAA;;AAAA,EASA,OAAO,CAAC,MAAR,CAAe;IAAC,gBAAD,EAAkB,SAAC,cAAD,GAAA;aAC/B,cACA,CAAC,IADD,CACM,eADN,EAEI;AAAA,QAAA,WAAA,EAAa,wBAAb;AAAA,QACA,UAAA,EAAY,oBADZ;OAFJ,EAD+B;IAAA,CAAlB;GAAf,CATA,CAAA;AAAA"
} }
\ No newline at end of file
path = require 'path' path = require 'path'
fs = require 'fs' fs = require 'fs'
child_process = require 'child_process' child_process = require 'child_process'
crypto = require('crypto'); crypto = require 'crypto'
mkdirp = require 'mkdirp' mkdirp = require 'mkdirp'
rmdir = require 'rmdir'
gui = require 'nw.gui' gui = require 'nw.gui'
Datastore = require('nw_nedb') Datastore = require 'nw_nedb'
db = new Datastore({ filename: path.join(gui.App.dataPath, 'apps.db'), autoload: true }); db =
apps: new Datastore({ filename: path.join(gui.App.dataPath, 'apps.db'), autoload: true })
local: new Datastore({ filename: path.join(gui.App.dataPath, 'local.db'), autoload: true })
angular.module('maotama.controllers', []) angular.module('maotama.controllers', [])
.controller 'AppsListController', ($scope)-> .controller 'AppsListController', ($scope, $http)->
db.find {}, (err, docs)=> $scope.orderProp = 'id';
throw err if err $http.get('apps.json').success (data)->
$scope.apps = docs console.log data
$scope.$digest(); db.apps.remove {}, { multi: true }, (err, numRemoved)->
throw err if err
db.apps.insert data, (err, newDocs)->
throw err if err
$scope.apps = data
$scope.$digest()
.controller 'AppsShowController', ['$scope', '$routeParams', ($scope, $routeParams)-> .controller 'AppsShowController', ['$scope', '$routeParams', ($scope, $routeParams)->
db.findOne {id: $routeParams.app_id}, (err, doc)-> db.apps.findOne {id: $routeParams.app_id}, (err, doc)->
throw err if err throw err if err
$scope.app = doc; $scope.app = doc
console.log $scope.app $scope.runtime =
$scope.app.default_installation_path = path.join process.cwd(), 'apps', $scope.app.id running: false
$scope.app.extra_languages = {} installing: {}
for lang, download of $scope.app.languages $scope.default_installation_path = path.join process.cwd(), 'apps', $scope.app.id
console.assert $scope.app.download.url
console.assert $scope.app.download.size db.local.findOne {id: $routeParams.app_id}, (err, doc)->
if download != true $scope.local = doc ? {}
$scope.app.has_extra_languages = true $scope.$digest();
$scope.app.extra_languages[lang] = download
$scope.installing = {};
$scope.$digest();
$scope.add = (installation)-> $scope.add = (installation)->
$scope.app.installation = path.dirname installation $scope.local.installation = path.dirname installation
db.update { db.local.update {
id: $scope.app.id id: $scope.app.id
}, { }, {
$set: { $set: {
installation: $scope.app.installation installation: $scope.local.installation
} }
}, {
upsert: true
}, (err, numReplaced, newDoc)-> }, (err, numReplaced, newDoc)->
throw err if err throw err if err
$scope.$digest(); $scope.$digest();
$scope.install = ()-> $scope.install = ()->
$scope.installing[$scope.app.id] =
$scope.runtime.installing[$scope.app.id] =
process: 0 process: 0
label: '正在连接' label: '正在连接'
mkdirp path.join(process.cwd(), 'cache'), (err)-> mkdirp path.join(process.cwd(), 'cache'), (err)->
...@@ -58,22 +64,23 @@ angular.module('maotama.controllers', []) ...@@ -58,22 +64,23 @@ angular.module('maotama.controllers', [])
console.log data console.log data
#[#06c774 35MiB/298MiB(11%) CN:1 DL:62MiB ETA:4s] #[#06c774 35MiB/298MiB(11%) CN:1 DL:62MiB ETA:4s]
#[#d1b179 752KiB/298MiB(0%) CN:1 DL:109KiB ETA:46m17s] #[#d1b179 752KiB/298MiB(0%) CN:1 DL:109KiB ETA:46m17s]
#[#4dd4a5 592KiB/298MiB(0%) CN:1 DL:43KiB ETA:1h57m19s]
if matches = data.match(/\[(?:#\w+ )?([\w\.]+)\/([\w\.]+)\((\d+)%\) CN:(\d+) DL:([\w\.]+) ETA:(\w+)\]/) if matches = data.match(/\[(?:#\w+ )?([\w\.]+)\/([\w\.]+)\((\d+)%\) CN:(\d+) DL:([\w\.]+) ETA:(\w+)\]/)
[d, downloaded, total, progress, connections, speed, eta] = matches [d, downloaded, total, progress, connections, speed, eta] = matches
$scope.installing[$scope.app.id].progress = progress $scope.runtime.installing[$scope.app.id].progress = progress
$scope.installing[$scope.app.id].label = "#{progress}% #{speed}/s" $scope.runtime.installing[$scope.app.id].label = "#{progress}% #{speed}/s"
$scope.$digest(); $scope.$digest();
aria2c.stderr.on 'data', (data)-> aria2c.stderr.on 'data', (data)->
console.log 'err: ', data console.log 'err: ', data
aria2c.on 'close', (code)-> aria2c.on 'close', (code)->
if code != 0 if code != 0
window.LOCAL_NW.desktopNotifications.notify "TODO://icon", $scope.app.name, "下载失败, 错误: #{code}" window.LOCAL_NW.desktopNotifications.notify $scope.app.icon, $scope.app.name, "下载失败, 错误: #{code}"
delete $scope.installing[$scope.app.id] delete $scope.runtime.installing[$scope.app.id]
$scope.$digest(); $scope.$digest();
else else
$scope.installing[$scope.app.id].progress = 100 $scope.runtime.installing[$scope.app.id].progress = 100
$scope.installing[$scope.app.id].label = '正在安装' $scope.runtime.installing[$scope.app.id].label = '正在安装'
$scope.$digest(); $scope.$digest();
downloaded = "cache/#{path.basename($scope.app.download.url)}"; downloaded = "cache/#{path.basename($scope.app.download.url)}";
...@@ -86,8 +93,8 @@ angular.module('maotama.controllers', []) ...@@ -86,8 +93,8 @@ angular.module('maotama.controllers', [])
file.on 'end', ()-> file.on 'end', ()->
if checksum.digest('hex') != $scope.app.download.checksum if checksum.digest('hex') != $scope.app.download.checksum
window.LOCAL_NW.desktopNotifications.notify "TODO://icon", $scope.app.name, "校验错误" window.LOCAL_NW.desktopNotifications.notify $scope.app.icon, $scope.app.name, "校验错误"
delete $scope.installing[$scope.app.id] delete $scope.runtime.installing[$scope.app.id]
$scope.$digest(); $scope.$digest();
else else
p = path.join "apps/#{$scope.app.id}" p = path.join "apps/#{$scope.app.id}"
...@@ -103,76 +110,44 @@ angular.module('maotama.controllers', []) ...@@ -103,76 +110,44 @@ angular.module('maotama.controllers', [])
console.log 'err: ', data console.log 'err: ', data
p7zip.on 'close', (code)-> p7zip.on 'close', (code)->
if code != 0 if code != 0
window.LOCAL_NW.desktopNotifications.notify "TODO://icon", $scope.app.name, "安装失败, 错误: #{code}" window.LOCAL_NW.desktopNotifications.notify $scope.app.icon, $scope.app.name, "安装失败, 错误: #{code}"
delete $scope.installing[$scope.app.id] delete $scope.runtime.installing[$scope.app.id]
$scope.$digest(); $scope.$digest();
else else
delete $scope.installing[$scope.app.id] delete $scope.runtime.installing[$scope.app.id]
window.LOCAL_NW.desktopNotifications.notify "TODO://icon", $scope.app.name, '安装完成' window.LOCAL_NW.desktopNotifications.notify $scope.app.icon, $scope.app.name, '安装完成'
$scope.add path.join(p, $scope.app.main) $scope.add path.join(p, $scope.app.main)
$scope.uninstall = ()->
$scope.runtime.uninstalling = true
db.local.remove {
id: $scope.app.id
}, (err, numRemoved)->
throw err if err
rmdir $scope.local.installation, ( err, dirs, files )->
console.log dirs
console.log files
console.log 'all files are removed'
$scope.local = {}
$scope.$digest()
$scope.run = ()-> $scope.run = ()->
console.log $scope.app $scope.runtime.running = true
$scope.app.running = true game = child_process.spawn $scope.app.main, [],
child_process.execFile $scope.app.main, cwd: $scope.local.installation
cwd: $scope.app.installation game.stdout.setEncoding('utf8');
, (error, stdout, stderr)-> game.stdout.on 'data', (data)->
throw error if error console.log data
$scope.app.running = false if matches = data.match /<maotama>(.+)<\/maotama>/
for command in $(matches[1])
switch command.tagName
when 'ACHIEVEMENT'
achievement = $scope.app.achievements[$(command).attr('type')]
achievement_item = achievement.items[$(command).attr('id')]
window.LOCAL_NW.desktopNotifications.notify achievement_item.icon, "获得#{achievement.name}: #{achievement_item.name}", achievement_item.description
else
window.LOCAL_NW.desktopNotifications.notify $scope.app.icon, "unknown command", matches[1]
game.on 'close', (code)->
$scope.runtime.running = false
$scope.$digest(); $scope.$digest();
] ]
if false #for debug
db.remove {}, { multi: true }, (err, numRemoved)->
throw err if err
db.insert [{
"id":"th135",
"category":"game",
"name":"东方心绮楼",
"network":{
"proto":"udp",
"port":10800
},
"main":"th135.exe",
"summary":"喵喵喵喵喵帕斯
nyanpass nyanpass"
"download": {
"url": "http://test2.my-card.in/downloads/maotama/th135_1.33.7z"
"size": 313177031
"checksum":"ab3c7f4646e080fb88959978865ebf24"
}
"main": 'th135.exe'
"languages": {
"ja-JP": true
"zh-CN": {
url: "http://test2.my-card.in/downloads/maotama/th135_lang_zh-CN_1.33.7z"
size: 74749190
checksum: "49111c67d941e30384251a2026ba67ba"
}
}
},{
"id":"th123",
"category":"game",
"name":"东方非想天则",
"network":{
"proto":"udp",
"port":10800
},
"summary":"",
"download": {
url: "http://test2.my-card.in/downloads/maotama/th123_1.10a.7z"
"size": 250272482
"checksum": "027a358a7ac014f725ebb8659f1caa6f"
},
"main": 'th123.exe'
"languages": {
"ja-JP": true
}
}], (err, newDocs)->
throw err if err
console.log newDocs
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
languages = require './js/languages.json' languages = require './js/languages.json'
humanize = require 'humanize' humanize = require 'humanize'
markdown = require( "markdown" ).markdown;
angular.module('maotama.filters', []) angular.module('maotama.filters', [])
.filter 'language_translate', ()-> .filter 'language_translate', ()->
...@@ -7,3 +9,6 @@ angular.module('maotama.filters', []) ...@@ -7,3 +9,6 @@ angular.module('maotama.filters', [])
languages[input] languages[input]
.filter 'filesize', ()-> .filter 'filesize', ()->
humanize.filesize humanize.filesize
.filter 'markdown', ()->
(input)->
markdown.toHTML(input) if input
\ No newline at end of file
// Generated by CoffeeScript 1.7.1 // Generated by CoffeeScript 1.7.1
(function() { (function() {
var humanize, languages; var humanize, languages, markdown;
languages = require('./js/languages.json'); languages = require('./js/languages.json');
humanize = require('humanize'); humanize = require('humanize');
markdown = require("markdown").markdown;
angular.module('maotama.filters', []).filter('language_translate', function() { angular.module('maotama.filters', []).filter('language_translate', function() {
return function(input) { return function(input) {
return languages[input]; return languages[input];
}; };
}).filter('filesize', function() { }).filter('filesize', function() {
return humanize.filesize; return humanize.filesize;
}).filter('markdown', function() {
return function(input) {
if (input) {
return markdown.toHTML(input);
}
};
}); });
}).call(this); }).call(this);
......
...@@ -6,5 +6,5 @@ ...@@ -6,5 +6,5 @@
"filters.coffee" "filters.coffee"
], ],
"names": [], "names": [],
"mappings": ";AAAA;AAAA,MAAA,mBAAA;;AAAA,EAAA,SAAA,GAAY,OAAA,CAAQ,qBAAR,CAAZ,CAAA;;AAAA,EACA,QAAA,GAAW,OAAA,CAAQ,UAAR,CADX,CAAA;;AAAA,EAGA,OAAO,CAAC,MAAR,CAAe,iBAAf,EAAkC,EAAlC,CACA,CAAC,MADD,CACQ,oBADR,EAC8B,SAAA,GAAA;WAC5B,SAAC,KAAD,GAAA;aACE,SAAU,CAAA,KAAA,EADZ;IAAA,EAD4B;EAAA,CAD9B,CAIA,CAAC,MAJD,CAIQ,UAJR,EAIoB,SAAA,GAAA;WAChB,QAAQ,CAAC,SADO;EAAA,CAJpB,CAHA,CAAA;AAAA" "mappings": ";AAAA;AAAA,MAAA,6BAAA;;AAAA,EAAA,SAAA,GAAY,OAAA,CAAQ,qBAAR,CAAZ,CAAA;;AAAA,EACA,QAAA,GAAW,OAAA,CAAQ,UAAR,CADX,CAAA;;AAAA,EAEA,QAAA,GAAW,OAAA,CAAS,UAAT,CAAqB,CAAC,QAFjC,CAAA;;AAAA,EAKA,OAAO,CAAC,MAAR,CAAe,iBAAf,EAAkC,EAAlC,CACA,CAAC,MADD,CACQ,oBADR,EAC8B,SAAA,GAAA;WAC5B,SAAC,KAAD,GAAA;aACE,SAAU,CAAA,KAAA,EADZ;IAAA,EAD4B;EAAA,CAD9B,CAIA,CAAC,MAJD,CAIQ,UAJR,EAIoB,SAAA,GAAA;WAChB,QAAQ,CAAC,SADO;EAAA,CAJpB,CAMA,CAAC,MAND,CAMQ,UANR,EAMoB,SAAA,GAAA;WAChB,SAAC,KAAD,GAAA;AACE,MAAA,IAA0B,KAA1B;eAAA,QAAQ,CAAC,MAAT,CAAgB,KAAhB,EAAA;OADF;IAAA,EADgB;EAAA,CANpB,CALA,CAAA;AAAA"
} }
\ No newline at end of file
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
<h1 class="page-header">{{app.name}} <h1 class="page-header">{{app.name}}
<button id="app_play" type="button" class="btn btn-default" ng-if="app.installation" ng-click="run()" ng-disabled="app.running"> <button id="app_play" type="button" class="btn btn-default" ng-if="local.installation" ng-click="run()" ng-disabled="runtime.running">
<span class="glyphicon glyphicon-play"></span> 开始 <span class="glyphicon glyphicon-play"></span> 开始
</button> </button>
<button id="app_install" type="button" class="btn btn-default" ng-if="!app.installation" data-toggle="modal" data-target="#app_install_modal"> <button id="app_install" type="button" class="btn btn-default" ng-if="!local.installation" data-toggle="modal" data-target="#app_install_modal">
<span class="glyphicon glyphicon-save"></span> 安装 <span class="glyphicon glyphicon-save"></span> 安装
</button> </button>
<button id="app_add" type="button" class="btn btn-default" ng-if="!app.installation"> <button id="app_add" type="button" class="btn btn-default" ng-if="!local.installation">
<span class="glyphicon glyphicon-plus"></span> 添加 <span class="glyphicon glyphicon-plus"></span> 添加
</button> </button>
<div id="cloud_wrapper" class="cloud input-group pull-right hide" ng-if="app.installation"> <div id="cloud_wrapper" class="cloud input-group pull-right hide" ng-if="local.installation">
<span class="input-group-addon"><span class="glyphicon glyphicon-cloud"></span></span> <span class="input-group-addon"><span class="glyphicon glyphicon-cloud"></span></span>
<input id="cloud_address" type="text" class="form-control" value="255.255.255.255:65535"> <input id="cloud_address" type="text" class="form-control" value="255.255.255.255:65535">
</div> </div>
<button id="cloud_button" type="button" class="cloud btn btn-default pull-right" ng-if="app.installation"> <button id="cloud_button" type="button" class="cloud btn btn-default pull-right" ng-if="local.installation && app.network">
<span class="glyphicon glyphicon-cloud"></span> 反重力场 <span class="glyphicon glyphicon-cloud"></span> 反重力场
</button> </button>
</h1> </h1>
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
<label for="app_install_installation">安装位置</label> <label for="app_install_installation">安装位置</label>
<div class="input-group"> <div class="input-group">
<input id="app_install_installation" type="text" class="form-control" value="{{app.default_installation_path}}"> <input id="app_install_installation" type="text" class="form-control" value="{{default_installation_path}}">
<span class="input-group-btn"> <span class="input-group-btn">
<button class="btn btn-default" type="button">浏览</button> <button class="btn btn-default" type="button">浏览</button>
</span> </span>
...@@ -73,12 +73,12 @@ ...@@ -73,12 +73,12 @@
</div> </div>
<label ng-if="app.has_extra_languages">语言包</label> <!--<label ng-if="app.mods | filter: {type: 'language'}">语言包</label>
<div class="checkbox" ng-repeat="(lang, download) in app.extra_languages"> <div class="checkbox" ng-repeat="(mod) in app.mods | filter: {type: 'language'}">
<label> <label>
<input type="checkbox" checked> {{lang | language_translate}} <input type="checkbox" checked> {{mod.languages[0] | language_translate}}
</label> </label>
</div> </div>-->
</form> </form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
...@@ -89,12 +89,12 @@ ...@@ -89,12 +89,12 @@
</div> </div>
</div> </div>
<input id="app_add_file" class="hide" type="file" accept="application/octet-stream"/> <input id="app_add_file" class="hide" type="file" accept="application/octet-stream"/>
<div class="progress progress-striped active" ng-repeat="item in installing"> <div class="progress progress-striped active" ng-repeat="item in runtime.installing">
<div class="progress-bar" role="progressbar" aria-valuenow="{{item.progress}}" aria-valuemin="0" aria-valuemax="100" style="width:{{item.progress}}%"> <div class="progress-bar" role="progressbar" aria-valuenow="{{item.progress}}" aria-valuemin="0" aria-valuemax="100" style="width:{{item.progress}}%">
{{item.label}} {{item.label}}
</div> </div>
</div> </div>
{{app.summary}} <div ng-bind-html="app.summary | markdown"></div>
<h2 class="sub-header">好友</h2> <h2 class="sub-header">好友</h2>
<p>您有 8 位好友玩过 {{app.name}},有 2 位正在玩</p> <p>您有 8 位好友玩过 {{app.name}},有 2 位正在玩</p>
...@@ -121,4 +121,28 @@ ...@@ -121,4 +121,28 @@
<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;"> <div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;">
<span class="sr-only">60% Complete</span> <span class="sr-only">60% Complete</span>
</div> </div>
</div>
<div ng-show="local.installation">
<h2 class="sub-header">设置</h2>
<button id="app_uninstall" type="button" class="btn btn-default" data-toggle="modal" data-target="#app_uninstall_modal" ng-disable="runtime.running || runtime.uninstalling">
<span class="glyphicon glyphicon-trash"></span> 卸载
</button>
<div class="modal fade" id="app_uninstall_modal" tabindex="-1" role="dialog" aria-labelledby="app_uninstall_modal_label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="app_uninstall_modal_label">卸载 {{app.name}}</h4>
</div>
<div class="modal-body">
确认卸载?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-danger" data-dismiss="modal" ng-click="uninstall()">卸载</button>
</div>
</div>
</div>
</div>
</div> </div>
\ No newline at end of file
[
{
"id": "th135",
"category": "game",
"name": "东方心绮楼",
"network": {
"proto": "udp",
"port": 10800
},
"main": "th135.exe",
"summary": "喵喵喵喵喵帕斯\nnyanpass nyanpass",
"download": {
"url": "http://test2.my-card.in/downloads/maotama/th135_1.33.7z",
"size": 313177031,
"checksum": "ab3c7f4646e080fb88959978865ebf24"
},
"languages": {
"ja-JP": true,
"zh-CN": {
"url": "http://test2.my-card.in/downloads/maotama/th135_lang_zh-CN_1.33.7z",
"size": 74749190,
"checksum": "49111c67d941e30384251a2026ba67ba"
}
}
},
{
"id": "th123",
"category": "game",
"name": "东方非想天则",
"network": {
"proto": "udp",
"port": 10800
},
"summary": "",
"download": {
"url": "http://test2.my-card.in/downloads/maotama/th123_1.10a.7z",
"size": 250272482,
"checksum": "027a358a7ac014f725ebb8659f1caa6f"
},
"main": "th123.exe",
"languages": {
"ja-JP": true
}
}
]
\ No newline at end of file
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
"node-windows": "^0.1.5", "node-windows": "^0.1.5",
"raw-socket": "^1.2.2", "raw-socket": "^1.2.2",
"humanize": "0.0.9", "humanize": "0.0.9",
"mkdirp": "^0.3.5" "mkdirp": "^0.3.5",
"markdown": "^0.5.0",
"rmdir": "^1.0.4"
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment