關(guān)鍵字:騰訊云阀蒂、移動(dòng)直播沥邻、liveroom
本文只涉及騰訊云 <live-room> 標(biāo)簽代碼結(jié)構(gòu)講解,只需要有基本的程序結(jié)構(gòu)思維即可玖翅。
本文使用騰訊云最新公開(kāi)的小程序源碼1.2.639,這個(gè)版本的小程序頁(yè)面與訪問(wèn)騰訊云視頻小程序看到的頁(yè)面稍有不同割以,但不影響標(biāo)簽分析金度。
基本概念
<live-room> 是騰訊云基于微信小程序內(nèi)置的<live-pusher>和<live-player>標(biāo)簽開(kāi)發(fā)用于雙人和多人音視頻通話的自定義組件。
<live-room> 主要用于一對(duì)多音視頻通過(guò)場(chǎng)景下严沥。騰訊云視頻 小程序的 手機(jī)直播 和 PC直播使用的就是 <live-room> 標(biāo)簽猜极。
使用方法
登錄房間服務(wù)
第一步需要登錄房間服務(wù)。
調(diào)用 /utils/liveroom.js 的 login 方法進(jìn)行登錄消玄,登錄的目的是要連接后臺(tái)房間服務(wù)(RoomService)跟伏。
var liveroom = require('/utils/liveroom.js');
...
liveroom.login({
serverDomain: '',
userID: '',
userSig: '',
sdkAppID: '',
accType: '',
userName: '' //用戶昵稱,由客戶自定義
});
注意翩瓜,這里的 UserSig 需要通過(guò)請(qǐng)求《騰訊云移動(dòng)直播微信小程序源碼解析(一)》中講到的 Django 后臺(tái)獲取受扳。
小程序端
在小程序中,可以這樣實(shí)現(xiàn)后臺(tái)請(qǐng)求:
qcloud.request({
// login:true,
url: config.serverUrl + '/accounts/genesig',
method: 'GET',
header: {
'content-type': 'application/json' // 默認(rèn)值
},
success: function (ret) {
console.log('get user ');
if (ret.data.code) {
console.log('獲取登錄信息失敗兔跌,調(diào)試期間請(qǐng)點(diǎn)擊右上角三個(gè)點(diǎn)按鈕勘高,選擇打開(kāi)調(diào)試');
options.fail && options.fail({
errCode: ret.data.code,
errMsg: ret.data.message + '[' + ret.data.code + ']'
});
return;
}
ret.data.serverDomain = config.roomServiceUrl + '/weapp/' + options.type + '/';
liveroom.login({
data: ret.data,
success: options.success,
fail: options.fail
});
}
邏輯是這樣的:
a) 向 django 后臺(tái)發(fā)送 GET 請(qǐng)求,請(qǐng)求地址為 config.serverUrl + '/accounts/genesig'坟桅;
b) 如果成功返回华望,檢查是否返回了錯(cuò)誤碼;
i. 如果返回錯(cuò)誤碼仅乓,則報(bào)錯(cuò)赖舟;
ii. 沒(méi)有沒(méi)有返回錯(cuò)誤碼,則登錄房間服務(wù)(RoomService)方灾;
Django 后臺(tái)
在 Django 后臺(tái)建蹄,可以這樣處理:
class GeneSigView(WeappMixin, View):
def get(self, request, *args, **kwargs):
self._get_openid(request)
result = {}
if self.openid is None:
result = {'code': -1, 'message': 'get openid error'}
return JsonResponse(data=result)
try:
tls_api = tls_sig.TLSSigAPI(settings.IM_SDKAPPID,
settings.PRIVATEKEY)
sig = tls_api.tls_gen_sig(self.openid)
result.update({'userSig': sig.decode(), 'userID': self.openid,
'sdkAppID': settings.IM_SDKAPPID,
'accType': settings.IM_ACCOUNTTYPE})
user = Account.objects.get(openid=self.openid)
result.update(
{'userName': user.nickname, 'userAvatar': user.avatarurl})
except:
result = {'code': -1, 'message': 'calc usersig error'}
return JsonResponse(data=result)
GeneSigView 即為實(shí)現(xiàn)視圖,它繼承的 WeappMixin 用戶獲取 openid :
class WeappMixin(object):
openid = None
def _get_openid(self, request):
session_id = request.META.get('HTTP_X_WX_SKEY')
try:
self.openid = redis_api.get_str(session_id).decode().split(':')[0]
except (ValueError, AttributeError):
self.openid = None
代碼中的 tls_sig 為 騰訊云提供的 sig 生成器裕偿,代碼是這樣的:
#! /usr/bin/python
# coding:utf-8
__author__ = "tls@tencent.com"
__date__ = "$Mar 3, 2016 03:00:43 PM"
import OpenSSL
import base64
import zlib
import json
import time
ecdsa_pri_key = """
-----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIEJDBDY4KVdj3dPBacADreB772ok45A57YWrUUvc5fMQoAcGBSuBBAAK
oUQDQgAEaPVFHhWqRDnKnVlyU5JIzXOUyOJd/pPUwhLUovf+PYBm7otRBptnvJ4E
oJ4qeSJNG0v4XdiqM3mtChkhUEFT3Q==
-----END EC PRIVATE KEY-----
"""
privateKey = '-----BEGIN PRIVATE KEY-----\r\n' + 'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQga7O4tX0KQH/Bhbq5\r\n' + 'zfP5nBDeAiBs6R8wO7zpd7PIB+GhRANCAAQI0AnMVO1km7iAMatqV3FcVrAC3B8/\r\n' + '1OShs1hr3Envd+KlUHtcZZ780G3+yc0nCo2NPYPCEODUm36oQ+iIhU+h\r\n' + '-----END PRIVATE KEY-----\r\n'
def list_all_curves():
list = OpenSSL.crypto.get_elliptic_curves()
for element in list:
print(element)
def get_secp256k1():
print(OpenSSL.crypto.get_elliptic_curve('secp256k1'))
def base64_encode_url(data):
base64_data = base64.b64encode(data)
base64_data = base64_data.replace(b'+', b'*')
base64_data = base64_data.replace(b'/', b'-')
base64_data = base64_data.replace(b'=', b'_')
return base64_data
def base64_decode_url(base64_data):
base64_data = base64_data.replace(b'*', b'+')
base64_data = base64_data.replace(b'-', b'/')
base64_data = base64_data.replace(b'_', b'=')
raw_data = base64.b64decode(base64_data)
return raw_data
class TLSSigAPI:
""""""
__acctype = 0
__identifier = ""
__appid3rd = ""
__sdkappid = 0
__version = 20151204
__expire = 3600 * 24 * 30 # 默認(rèn)一個(gè)月洞慎,需要調(diào)整請(qǐng)自行修改
__pri_key = ""
__pub_key = ""
_err_msg = "ok"
def __get_pri_key(self):
return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, self.__pri_key)
def __init__(self, sdkappid, pri_key):
self.__sdkappid = sdkappid
self.__pri_key = pri_key
def __create_dict(self):
return {"TLS.account_type": "%d" % self.__acctype, "TLS.identifier": "%s" % self.__identifier,
"TLS.appid_at_3rd": "%s" % self.__appid3rd, "TLS.sdk_appid": "%d" % self.__sdkappid,
"TLS.expire_after": "%d" % self.__expire, "TLS.version": "%d" % self.__version,
"TLS.time": "%d" % time.time()}
def __encode_to_fix_str(self, m):
fix_str = "TLS.appid_at_3rd:" + m["TLS.appid_at_3rd"] + "\n" \
+ "TLS.account_type:" + m["TLS.account_type"] + "\n" \
+ "TLS.identifier:" + m["TLS.identifier"] + "\n" \
+ "TLS.sdk_appid:" + m["TLS.sdk_appid"] + "\n" \
+ "TLS.time:" + m["TLS.time"] + "\n" \
+ "TLS.expire_after:" + m["TLS.expire_after"] + "\n"
return fix_str
def tls_gen_sig(self, identifier):
self.__identifier = identifier
m = self.__create_dict()
fix_str = self.__encode_to_fix_str(m)
pk_loaded = self.__get_pri_key()
sig_field = OpenSSL.crypto.sign(pk_loaded, fix_str, "sha256")
sig_field_base64 = base64.b64encode(sig_field)
m["TLS.sig"] = sig_field_base64.decode('utf-8')
json_str = json.dumps(m)
sig_compressed = zlib.compress(json_str.encode('utf-8'))
base64_sig = base64_encode_url(sig_compressed)
return base64_sig
def main():
api = TLSSigAPI(1400001052, privateKey)
sig = api.tls_gen_sig("xiaojun")
print(sig)
if __name__ == "__main__":
main()
在JSON 文件中進(jìn)行配置
在 page 目錄下的 json配置文件內(nèi)引用組件:
{
"navigationBarTitleText": "在線課堂",
"usingComponents": {
"live-room": "/pages/components/live-room/liveroom"
}
}
在 WXML 文件中使用
在 page 目錄下的 wxml 文件中使用標(biāo)簽 <live-room>:
<live-room id="id_liveroom" wx:if="{{showLiveRoom}}" roomid="{{roomID}}" role="{{role}}" roomname="{{roomName}}" pureaudio="{{pureAudio}}" debug="{{debug}}" muted="{{muted}}" beauty="{{beauty}}" template="vertical1v3" bindRoomEvent="onRoomEvent">
到這里,<live-room> 標(biāo)簽可以正常使用了嘿棘。
直播頁(yè)面
live-room 標(biāo)簽正常工作時(shí)劲腿,用戶分為三類:
大主播:可以理解為直播間的主人,權(quán)限較高鸟妙;
小主播:可以與大主播互動(dòng)的用戶焦人。
觀眾:不可以與大主播互動(dòng)的用戶挥吵,只能觀看大主播的直播。
<live-room> 標(biāo)簽需要大主播創(chuàng)建直播間花椭,只有大主播進(jìn)入直播間忽匈,其它用戶才能進(jìn)入房間。
大主播矿辽、小主播看到的頁(yè)面如下圖所示丹允,其中大主播在左側(cè),小主播(最多3個(gè))在右側(cè)袋倔。
觀眾看到的頁(yè)面如下圖所示,只能看到大主播宾娜。
觀眾可以點(diǎn)擊頁(yè)面上的麥克圖標(biāo)向大主播申請(qǐng)連麥批狐,大主播端后顯示小主播的連麥請(qǐng)求,如果大主播同意連麥前塔,則該觀眾成為小主播嚣艇。如果存在多于3個(gè)小主播,目前只能顯示3個(gè)小主播嘱根。
大主播可以通過(guò)踢人操作將小主播踢出髓废,小主播此時(shí)變?yōu)橛^眾巷懈。
這樣该抒,我們可以順暢的使用 <live-room>標(biāo)簽了。下面的內(nèi)容只是為了了解 live-room 標(biāo)簽如何工作及進(jìn)一步定制代碼顶燕。
代碼結(jié)構(gòu)
<live-room>標(biāo)簽代碼位于 pages/components/live-room文件夾內(nèi)凑保,該文件夾用于創(chuàng)建live-room自定義組件。
自定義組件的詳細(xì)介紹見(jiàn)微信小程序文檔涌攻。
live-room 自定義組件包含 vertical1v3template 文件夾欧引、liveroom.js、liveroom.json恳谎、liveroom.wxml 及 liveroom.wxss芝此。從結(jié)構(gòu)來(lái)看,除了vertical1v3template 文件夾因痛,該自定義組件的結(jié)構(gòu)與微信小程序頁(yè)面類似婚苹。
vertical1v3template 為騰訊云的 live-room 模板。模板的代碼是這樣的:
<template name="vertical1v3">
<view class="{{linkPusherInfo.url || isCaster ? 'v-full2': 'v-full'}}">
<view wx:if="{{isCaster}}" class='v-main-video'>
<live-pusher wx:if="{{isCaster&&mainPusherInfo.url}}" id="pusher" mode="RTC" url="{{mainPusherInfo.url}}" min-bitrate="850" min-bitrate="1200" beauty="{{beauty}}" enable-camera="{{!pureaudio}}" muted="{{muted}}" aspect="9:16" waiting-image="https://mc.qcloudimg.com/static/img/daeed8616ac5df256c0591c22a65c4d3/pause_publish.jpg"
background-mute="{{true}}" debug="{{debug}}" bindstatechange="onMainPush" binderror="onMainError">
<cover-view class='character' style='padding: 0 5px;'>我({{userName}})</cover-view>
<cover-view class="operate">
<cover-view class='img-box'>
<cover-image class='img-view' src='/pages/Resources/camera.png' bindtap="switchCamera"></cover-image>
<!-- <cover-view class='text-view'>翻轉(zhuǎn)</cover-view> -->
</cover-view>
<cover-view class='img-box'>
<cover-image class='img-view' src='/pages/Resources/{{beauty > 0? "beauty" : "beauty-dis"}}.png' bindtap="toggleBeauty"></cover-image>
<!-- <cover-view class='text-view'>美顏</cover-view> -->
</cover-view>
<!-- <cover-view class='img-box'>
<cover-image class='img-view' src='/pages/Resources/{{muted ? "mic-dis" : "mic"}}.png' bindtap="toggleMuted"></cover-image>
<cover-view class='text-view'>聲音</cover-view>
</cover-view> -->
<cover-view class='img-box'>
<cover-image class='img-view' src='/pages/Resources/{{debug? "log" : "log2"}}.png' bindtap="toggleDebug"></cover-image>
<!-- <cover-view class='text-view'>日志</cover-view> -->
</cover-view>
</cover-view>
</live-pusher>
</view>
<view wx:for="{{visualPlayers}}" wx:key="{{index}}" class="{{linkPusherInfo.url ? 'v-main-video' : 'v-full'}}">
<live-player wx:if="{{item.url}}" autoplay id="player" mode="{{item.mode}}" min-cache="{{item.minCache}}" max-cache="{{item.maxCache}}" object-fit="{{item.objectFit}}" src="{{item.url}}" debug="{{debug}}" muted="{{muted}}" background-mute="{{item.mute}}" bindstatechange="onMainPlayState"
binderror="onMainPlayError">
<cover-view class="operate">
<cover-view wx:if="{{linkPusherInfo.url}}" class='img-box'>
<cover-image class='img-view' src='/pages/Resources/camera.png' bindtap="switchCamera"></cover-image>
<!-- <cover-view class='text-view'>翻轉(zhuǎn)</cover-view> -->
</cover-view>
<cover-view wx:if="{{linkPusherInfo.url}}" class='img-box'>
<cover-image class='img-view' src='/pages/Resources/{{beauty > 0? "beauty" : "beauty-dis"}}.png' bindtap="toggleBeauty"></cover-image>
<!-- <cover-view class='text-view'>美顏</cover-view> -->
</cover-view>
<!-- <cover-view class='img-box'>
<cover-image class='img-view' src='/pages/Resources/{{muted ? "mic-dis" : "mic"}}.png' bindtap="toggleMuted"></cover-image>
<cover-view class='text-view'>聲音</cover-view>
</cover-view> -->
<cover-view wx:if="{{!linkPusherInfo.url}}" class='img-box'>
<cover-image class='img-view' src='/pages/Resources/mic.png' bindtap="requestJionPusher"></cover-image>
<!-- <cover-view class='text-view'>連麥</cover-view> -->
</cover-view>
<cover-view class='img-box'>
<cover-image class='img-view' src='/pages/Resources/{{debug? "log" : "log2"}}.png' bindtap="toggleDebug"></cover-image>
<!-- <cover-view class='text-view'>日志</cover-view> -->
</cover-view>
</cover-view>
</live-player>
</view>
</view>
<view wx:if="{{linkPusherInfo.url || isCaster}}" class='v-sub-video-list'>
<view class='.v-sub-video' wx:if="{{!isCaster && linkPusherInfo.url}}">
<live-pusher wx:if="{{!isCaster && linkPusherInfo.url}}" min-bitrate="400" min-bitrate="200" id="audience_pusher" mode="RTC" min-bitrate="900" url="{{linkPusherInfo.url}}" beauty="{{beauty}}" enable-camera="{{!pureaudio}}" muted="{{muted}}" aspect="9:16"
waiting-image="https://mc.qcloudimg.com/static/img/daeed8616ac5df256c0591c22a65c4d3/pause_publish.jpg" background-mute="true" debug="{{debug}}" bindstatechange="onLinkPush" binderror="onLinkError">
<cover-image class='character' src="/pages/Resources/mask.png"></cover-image>
<cover-view class='character' style='padding: 0 5px;'>我({{userName}})</cover-view>
<cover-view class='close-ico' bindtap="quitLink">x</cover-view>
</live-pusher>
</view>
<view class='.v-sub-video' wx:for="{{members}}" wx:key="{{item.userID}}">
<view class='poster'>
<cover-image wx:if="{{ index < 4 }}" class='set' src="https://miniprogram-1252463788.file.myqcloud.com/roomset_{{index + 1}}.png"></cover-image>
</view>
<live-player wx:if="{{item.accelerateURL}}" id="{{item.userID}}" autoplay mode="RTC" object-fit="fillCrop" min-cache="0.1" max-cache="0.3" src="{{item.accelerateURL}}" debug="{{debug}}" background-mute="{{true}}">
<cover-view class="close-ico" wx:if="{{item.userID == userID || isCaster}}" bindtap="kickoutSubPusher" data-userid="{{item.userID}}">x</cover-view>
<cover-view class='loading' wx:if="{{false}}">
<cover-image src="/pages/Resources/loading_image0.png"></cover-image>
</cover-view>
<cover-image class='character' src="/pages/Resources/mask.png"></cover-image>
<cover-view class='character' style='padding: 0 5px;'>{{item.userName}}</cover-view>
</live-player>
</view>
</view>
</template>
模板的邏輯是這樣的:
對(duì)于整個(gè)頁(yè)面鸵膏,邏輯為:
判斷 linkPusherInfo.url 或 isCaster 是否為 true膊升,如果是,使用v-full2谭企,否則使用 v-full廓译。
其中小主播具有 linkPusherInfo.url 评肆,用戶為大主播時(shí) isCaster 為 true。
也就是說(shuō)非区,對(duì)于大主播和小主播 class = v-full2瓜挽;對(duì)于觀眾,class = v-full征绸。
即 我們上面看到的不同用戶角色對(duì)應(yīng)的不同頁(yè)面秸抚。
對(duì)于大主播、小主播的頁(yè)面歹垫,如下圖所示剥汤,左側(cè)紫色框部分 class = v-main-video,右側(cè)紅色框部分為 v-sub-video-list排惨。
頁(yè)面中通過(guò) isCaster&&mainPusherInfo.url 來(lái)區(qū)分大主播吭敢、小主播對(duì)應(yīng)的頁(yè)面。
大主播(isCaster=true)看到的頁(yè)面暮芭,大主播為live-pusher鹿驼,視頻影像在上圖中紫色框中。小主播為live-player辕宏,視頻影像在上圖中紅色框中的一個(gè)小框中畜晰。
小主播(members)看到的頁(yè)面,大主播為 liver-player(此時(shí)大主播變?yōu)榱?VisualPlayers)瑞筐,視頻影像仍在上圖中紫色框中凄鼻。小主播自己為 live-pusher ,視頻影像在上圖中紅色框的第一個(gè)小框中。下面兩個(gè)小框?yàn)槠渌≈鞑ァ?/p>
也就是說(shuō)聚假,大主播和小主播看到的右側(cè)紅色框中主播的順序是不一致的块蚌。
角色 | 大主播 | 小主播 |
---|---|---|
位置 | 左側(cè)大框 | 右側(cè)小框中的一個(gè) |
名稱 | -- | members |
對(duì)于大主播來(lái)講:
角色 | 大主播 | 小主播 |
---|---|---|
位置 | 左側(cè)大框 | 右側(cè)小框中的一個(gè) |
名稱 | -- | members |
對(duì)于小主播來(lái)將:
角色 | 大主播 | 小主播 |
---|---|---|
位置 | 左側(cè)大框 | 右側(cè)小框第一個(gè) |
名稱 | VisualPlayers | members |
角色 | 大主播 | 小主播 |
---|---|---|
位置 | 整個(gè)頁(yè)面 | 無(wú) |
名稱 | VisualPlayers | 無(wú) |
對(duì)于觀眾來(lái)講:
角色 | 大主播 | 小主播 |
---|---|---|
位置 | 整個(gè)頁(yè)面 | 無(wú) |
名稱 | VisualPlayers | 無(wú) |
未完待續(xù)...
- 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)喷户,“玉大人唾那,你說(shuō)我怎么就攤上這事。” “怎么了闹获?”我有些...
- 文/不壞的土叔 我叫張陵期犬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我避诽,道長(zhǎng)龟虎,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任沙庐,我火速辦了婚禮鲤妥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拱雏。我一直安慰自己棉安,他們只是感情好,可當(dāng)我...
- 文/花漫 我一把揭開(kāi)白布铸抑。 她就那樣靜靜地躺著贡耽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鹊汛。 梳的紋絲不亂的頭發(fā)上蒲赂,一...
- 那天,我揣著相機(jī)與錄音刁憋,去河邊找鬼滥嘴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛至耻,可吹牛的內(nèi)容都是我干的若皱。 我是一名探鬼主播,決...
- 文/蒼蘭香墨 我猛地睜開(kāi)眼有梆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼是尖!你這毒婦竟也來(lái)了意系?” 一聲冷哼從身側(cè)響起泥耀,我...
- 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛔添,沒(méi)想到半個(gè)月后痰催,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
- 正文 獨(dú)居荒郊野嶺守林人離奇死亡迎瞧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
- 正文 我和宋清朗相戀三年夸溶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凶硅。...
- 正文 年R本政府宣布,位于F島的核電站粹污,受9級(jí)特大地震影響段多,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜壮吩,卻給世界環(huán)境...
- 文/蒙蒙 一进苍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鸭叙,春花似錦觉啊、人聲如沸。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至缀程,卻和暖如春搜吧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杨凑。 一陣腳步聲響...
- 正文 我出身青樓蜒程,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親伺帘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昭躺,可洞房花燭夜當(dāng)晚...
推薦閱讀更多精彩內(nèi)容
- 轉(zhuǎn)載鏈接 注:本文轉(zhuǎn)載知乎上的回答 作者:初雪 鏈接:https://www.zhihu.com/question...
- 筆名:秋水 1 公司有一位員工要離職领炫。 員工離職本是再平常不過(guò)的事兒,少有人會(huì)像A一樣情緒如此失控张咳。 淚如雨下帝洪,半...
- 工作臺(tái)上擺放的筆記和訂單,以老舊的古董秤砣為鎮(zhèn)紙脚猾,它們整齊擺放的樣子很符合一個(gè)強(qiáng)迫癥患者的審美
- 今天看了《感動(dòng)中國(guó)》葱峡,其實(shí)每年都要看,每年都有不一樣的感動(dòng)龙助。今年印象最深刻的是那個(gè)村官大學(xué)生砰奕,耶魯大學(xué)生甘愿當(dāng)大學(xué)...
- 摘自《瓦爾登湖》第四頁(yè)军援。 我怕常空,在美的季候里,我沒(méi)有收到通知盖溺,就開(kāi)始丟失自己漓糙。我怕,在時(shí)代的波瀾里烘嘱,我連呼救的機(jī)會(huì)...