搜尋此網誌

2013年9月27日 星期五

【Java】實作透過Gmail SMTP Server 發送信件 版本三

改寫版本二的內容(尚未測試,ps筆者跑太多次,gmail被暫停使用)
  1. 參考至這篇TLS加密並不是明文傳送。若要用密文傳送需要用SSL,且設定需要用SMTPS。
    (若需測試使用,下面兩行註解拿掉)
    // if (this.secureType == secureType.SSL)
    // protocol = SMTPS;
  2. 更貼近E-mail功能,使寄件者以及收信者均包含名字以及email地址,也可以設定同時多個收信者。所以增加:EmailSender和EmailReceiver。
  3. Properties 參數可以參考:Package com.sun.mail.smtp


EmailSender.java

class EmailSender{
	String name;
	String address;
	
	EmailSender(){
		name = "";
		address = "";
	}	
}
EmailReceiver.java

public interface EmailReceiver {
	String name();
	String address();
}

Email.java

package option;

import java.text.DateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.Vector;

import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import option.GmailSetting.SecureType;

public class Email {

	String subject;
	String content;
	SecureType secureType;
	boolean valid;
	String account;
	String passowrd;
	EmailSender emailSender;
	Vector<EmailReceiver> emailReceivers;

	static final String SMTP = "smtp";
	static final String SMTPS = "smtps";

	Email(SecureType secureType, boolean valid, String account, String password) {
		subject = "";
		content = "";
		this.secureType = secureType;
		this.valid = valid;
		this.account = account;
		this.passowrd = password;
		emailSender = new EmailSender();
		emailReceivers = new Vector<EmailReceiver>();
	}

	public void setSubject(String subject) {
		this.subject = subject;
	}

	public void setContents(String content) {
		this.content = content;
	}

	public void setSender(String name, String address) {
		emailSender.name = name;
		emailSender.address = address;
	}

	public void addReceiver(final String name, final String address) {
		emailReceivers.add(new EmailReceiver() {
			public String address() {
				return address;
			}

			public String name() {
				return name;
			}
		});
	}

	Properties generateRequireProp() {

		String protocol = SMTP;
		final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
		String portNumber = GmailSetting.PORT_NUMBER.get(secureType.value()).toString();

		//
		// if (this.secureType == secureType.SSL)
		// protocol = SMTPS;

		// set up gmail information
		Properties props = new Properties();
		props.setProperty("mail." + protocol + ".host", "smtp.gmail.com");
		props.setProperty("mail." + protocol + ".port", portNumber);
		props.setProperty("mail.transport.protocol", protocol);

		if (valid)
			props.setProperty("mail" + protocol + ".smtp.auth", "true");

		if (this.secureType != SecureType.None) {
			if (this.secureType == secureType.TLS)
				props.setProperty("mail." + protocol + ".smtp.starttls.enable", "true");
			else {
				props.setProperty("mail." + protocol + ".socketFactory.class", SSL_FACTORY);
				props.setProperty("mail." + protocol + ".socketFactory.fallback", "false");
				props.setProperty("mail." + protocol + ".socketFactory.port", portNumber);
				props.setProperty("mail." + protocol + ".smtps.ssl.enable", "true");

			}
		}
		return props;
	}

	boolean sendMail() {
		try {
			if (emailReceivers.isEmpty()) {
				System.out.println("Email Receiver is empty.");
				return false;
			}

			System.out.println("Start to send email");

			int receiverAddressCount = emailReceivers.size();
			Address[] mailAddress = new Address[receiverAddressCount];
			for (int i = 0; i < receiverAddressCount; i++) {
				mailAddress[i] = new InternetAddress(emailReceivers.get(i).address(), emailReceivers.get(i).name());
			}

			Address senderAddress = new InternetAddress(emailSender.address, emailSender.name);

			Properties props = generateRequireProp();

			// build the new session service
			Session session = Session.getInstance(props, null);

			Message message = new MimeMessage(session);

			// build the mail of sender , receiver and subject info
			message.setHeader("Content-Transfer-Encoding", "utf-8");
			message.setFrom(senderAddress);
			message.setRecipients(Message.RecipientType.TO, mailAddress);
			message.setSubject(subject);

			// set mime content
			MimeMultipart multipart = new MimeMultipart();
			MimeBodyPart messageBodyPart = new MimeBodyPart();
			messageBodyPart.setContent(content + "by " + secureType.value() + " connection.", "text/html;charset=utf-8");
			multipart.addBodyPart(messageBodyPart);
			message.setContent(multipart);

			message.saveChanges();
			String protocol = SMTP;

			if (valid) {
				Transport transport = session.getTransport();
				if (this.secureType == secureType.SSL)
					protocol = SMTPS;
				transport = session.getTransport(protocol);
				transport.connect("smtp.gmail.com", this.account, this.passowrd);
				Transport.send(message, message.getAllRecipients());
				transport.close();
			} else {
				Transport.send(message);

			}
			System.out.println("Done");

		} catch (Exception e) {
			// throw new RuntimeException(e);
			e.printStackTrace();
		}
		return true;

	}

	public static void main(String args[]) {

		final String senderAddr = "sender@gmail.com";
		final String password = "sender password";

		Email testEmail = new Email(SecureType.SSL, true, senderAddr, password);
		testEmail.setSubject("Test mail " + DateFormat.getDateTimeInstance().format(new Date(System.currentTimeMillis())));
		testEmail.setContents("This is a test e-mail by javamail library");
		testEmail.addReceiver("Test123", "receiver@mail");
		testEmail.setSender("SenderTest by Jorden", senderAddr);

		if (testEmail.sendMail())
			System.out.println("Success to send email!");

		else
			System.out.println("Error");
	}
}

2013年9月26日 星期四

【Java】實作透過Gmail SMTP Server 發送信件 版本二

本實作是改寫上篇透過SSL加密寄信;新增TLS以及None的方法。
因為Gmail已經不提供None(不加密)的寄信,所以在執行None方法時,會出現問題。

這部分除了改寫原本code以外,新增一個class放置gmail secure設定以及對應的port number。

Email.java


package option;

import java.text.DateFormat;
import java.util.Date;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import option.GmailSetting.*;

public class Email {

	String subject;
	String content;
	String receiver;
	SecureType secureType;

	Email(SecureType secureType) {
		subject = "";
		content = "";
		receiver = "";
		this.secureType = secureType;
	}

	public void setSubject(String subject) {
		this.subject = subject;
	}

	public void setContents(String content) {
		this.content = content;
	}

	public void setReceiverAddress(String address) {
		this.receiver = address;
	}

	Properties generateRequireProp() {

		final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
		String portNumber = GmailSetting.PORT_NUMBER.get(secureType.value()).toString();

		// set up gmail smtp information
		Properties props = new Properties();
		props.setProperty("mail.smtp.host", "smtp.gmail.com");
		props.setProperty("mail.transport.protocol", "smtp");
		props.setProperty("mail.smtp.auth", "true");
		props.setProperty("mail.smtp.port", portNumber);

		if (this.secureType != SecureType.None) {
			if (this.secureType == secureType.TLS)
				props.setProperty("mail.smtp.starttls.enable", "true");
			else {
				props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
				props.setProperty("mail.smtp.socketFactory.fallback", "false");
				props.setProperty("mail.smtp.socketFactory.port", portNumber);
				props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
			}
		}
		return props;
	}

	boolean sendMail() {
		if (this.receiver.equals("")) {
			System.out.println("Email Receiver is empty.");
			return false;
		}

		System.out.println("Start to send email");
		Properties props = generateRequireProp();
		final String username = "sender@gmail.com";
		final String password = "sender password";

		// build the new session service
		Session session = Session.getInstance(props, new Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(username, password);
			}
		});

		try {
			Message message = new MimeMessage(session);

			// build the mail of sender , receiver and subject info
			message.setFrom(new InternetAddress(username));
			message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(receiver, false));
			message.setSubject(subject);

			// set mime content
			MimeMultipart multipart = new MimeMultipart();
			MimeBodyPart messageBodyPart = new MimeBodyPart();
			messageBodyPart.setContent(content + "by " + secureType.value() + " connection.", "text/html;charset=utf-8");
			multipart.addBodyPart(messageBodyPart);
			message.setContent(multipart);

			Transport.send(message);
			System.out.println("Done");

		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return true;

	}

	public static void main(String args[]) {

		Email email = new Email(SecureType.SSL);
		email.setSubject("Test mail " + DateFormat.getDateTimeInstance().format(new Date(System.currentTimeMillis())));
		email.setContents("This is a test e-mail by javamail library");
		email.setReceiverAddress("receiver@mail");

		if (email.sendMail())
			System.out.println("Success to send email!");

		else
			System.out.println("Error");

	}
}


GmailSetting.java

package option;

import java.util.HashMap;
import java.util.Map;

public class GmailSetting {
	SecureType secureType;

	public GmailSetting() {
		// TODO Auto-generated constructor stub
	}

	public enum SecureType {
		None, SSL, TLS;

		public String value() {
			return name();
		}

		public static SecureType fromValue(String v) {
			return valueOf(v);
		}
	}

	static final Map<String, Integer> PORT_NUMBER = new HashMap<String, Integer>() {
		private static final long serialVersionUID = -5199045595923410899L;
		{
			put("None", 25);
			put("SSL", 465);
			put("TLS", 587);
		}
	};

}

【Java】class method VS. instance method


     
  1. 類別方法(class method or static method):這種方法以 static 宣告。呼叫的方式是 C.m(...),其中 C 是類別名稱,m 是方法名稱,...則是0至多個傳入的參數。在宣告時,會配置記憶體空間
  2. 實例方法(instance method or non-static method):這種方法不以 static 宣告,隸屬於一個類別所產生的實例。呼叫的方式是 o.m(...),其中 o 是這個類別或其子類別的實例,而 m 是其方法名稱,...則是0至多個傳入的參數。  在宣告時,不會配置記憶體空間

class A {
    static String c1() {
        return "class method不需new就可使用";
    }
    String c2() {
        return "instance method需new才可使用";
    }
}

public class ClassInstanceMethod {
    public static void main(String argv[]) {
        System.out.println("=呼叫class method=");
        System.out.println(A.c1());
        System.out.println("=呼叫instance method=");
        //System.out.println(A.c2()); =>error
        A a = new A();
        System.out.println(a.c2());
    }
}

參考:
http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
http://www.oreilly.com.tw/column_sleepless.php?id=j021

【Java】Primitive VS. Wrapper Class

看了很多書,都沒有很清楚說明為何要這兩個class的差別,而且又是從c語言跳到Java,覺得Wrapper Class的出現簡直莫名其妙。很久以前之前還被嗆難道不知道宣告int要先new出來。後來看了不少資料,得到以下結論:

參考

 Wrapper Class的出現,是因為Java裡面提供的許多API只能針對物件(例如,Collection),無法適用於基本型別(即int, long, char, boolean等)。為了使這些基本型別也可以適用,所以Java創造了與這些基本型別相對應的wrapper class
 Primitive  <-->Wrapper Class
--------------------------------
boolean <-> Boolean
byte <-> Byte
char <-> Character
short <->Short
int <-> Integer
long <-> Long
float <-> Float
double <-> Double


Primitive在宣告時,不需new,即可以在記憶體產生。例:int i=10;
Wrapper在宣告時,需new即可以在記憶體產生。例:Integer wInt= new Integer(10); 
int ii = wInt.intValue; //ii=10 


而Autoboxing的機制,就是自動把primitive轉成wrapper;相反地,Unboxing的機制就是自動把
wrapper轉成primitive。

 Autoboxing機制的目的:是要減少實體化的物件數,因此透過建立一個pool來儲存這些因auboxing產生出的物件,但這也造成另一問題:這些備產生出的物件不會輕易隨便殺掉。如果沒有限制建立這些物件,記憶體會快就用光,避免這些memory overflow的問題,Java限制每個wrapper class的pool範圍。若超過這個範圍,就會以一般建立物件的方式new出來。例:Integer i = new Integer(321);
Boolean:  (全部暫存)
Byte:         (全部暫存)
Character:  [0, 127] 暫存
Short :          [-128, 127] 暫存
Long:           [-128, 127] 暫存
Float:        (沒有暫存)
Double:   (沒有暫存)


因此,下例

int getNumber() {
        //do something
        return 128;
}

Integer value1 = 128;  //Autoboxing
Integer value2 =
getNumber();  //Autobixing
if (value1 == value2) {
        System.out.println(“A”);
}
else {
        System.out.println(“B”);
}

當value1和value2都個別autoboxing成物件,所以會分別指向pool中不同的記憶體位置。
在做判斷"=",因為指向不同記憶體位置,所以回傳結果,答案會是B。 

 所以在牽涉到兩物件比較時,需要用equals或compareTo的method,比較兩物件的內容,而不是比較兩物件的地址。

2013年9月25日 星期三

【Java】實作透過Gmail SMTP Server 發送信件(利用javamail API)

連線加密方式有三種:
  1. None(不加密)
  2. TLS , port number:587
  3. SSL , port number:465 (參考網址)
這裡實作以SSL加密寄送信件。
需要包裝javamail API到lib,下例用JavaMail 1.4.2進行包裝。

注意: 若發送信件內容,不只是純文字,而有用到html、CSS。
經過測試後,確定gmail 不支援部分block css內容,若可行,請寫inline css。
其他html email設計的要素,參考:
  1. Guide to CSS support in email 
  2. How HTML email works, basic concepts, best practices, tips and tricks

package option;

import java.text.DateFormat;
import java.util.Date;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

public class Email {

 String subject;
 String content;
 String receiver;

 Email() {
  subject = "";
  content = "";
  receiver = "";
 }

 public void setSubject(String subject) {
  this.subject = subject;
 }

 public void setContents(String content) {
  this.content = content;
 }

 public void setReceiverAddress(String address) {
  this.receiver = address;
 }

 static Properties generateRequireProp() {

  final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
  
  // set up gmail information
  Properties props = new Properties();
  props.setProperty("mail.smtp.host", "smtp.gmail.com");
  props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
  props.setProperty("mail.smtp.socketFactory.fallback", "false");
  props.setProperty("mail.smtp.socketFactory.port", "465");
  props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
  props.setProperty("mail.smtp.auth", "true");
  props.setProperty("mail.smtp.port", "465");

  return props;
 }

 boolean send() {
  if (receiver.equals("")) {
   System.out.println("Email Receiver is empty.");
   return false;
  }

  Properties props = generateRequireProp();
  final String username = "sender@gmail.com";
  final String password = "sender password";

  // build the new session service
  Session session = Session.getInstance(props, new Authenticator() {
   protected PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(username, password);
   }
  });

  try {   
   Message message = new MimeMessage(session);
   
   //build the mail of sender , receiver and subject info 
   message.setFrom(new InternetAddress(username));
   message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(receiver, false));
   message.setSubject(subject);
   
   // set mime content
   MimeMultipart multipart = new MimeMultipart();
   MimeBodyPart messageBodyPart = new MimeBodyPart();
   messageBodyPart.setContent(content, "text/html;charset=utf-8");
   multipart.addBodyPart(messageBodyPart);
   message.setContent(multipart);

   Transport.send(message);
   System.out.println("Done");

  } catch (Exception e) {
   throw new RuntimeException(e);
  }
  return true;

 }

 public static void main(String args[]) {

  Email email = new Email();
  email.setSubject("Test mail "+DateFormat.getDateTimeInstance().format(new Date(System.currentTimeMillis())));
  email.setContents("This is a test e-mail by javamail library");
  email.setReceiverAddress("receiver@mail");

  if (email.send())
   System.out.println("Sending is successing");

  else
   System.out.println("Error");

 }
}

2013年9月23日 星期一

【Music】One more time, One more Chance



 これ以上何を失えば 心は許されるの
究竟還要再失去什麼 我的心才會得到寬恕
どれ程の痛みならば もういちど君に会える
到底要痛到什麼程度 才能夠再次見到妳
One more time 季節よ うつろわないで
One more time 季節啊 希望你別轉變
One more time ふざけあった 時間よ
One more time 與妳嬉鬧的時光啊

くいちがう時はいつも 僕が先に折れたね
發生爭執的時候 每次都是我先讓步
わがままな性格が なおさら愛しくさせた
這種任性的個性 卻更加地讓人憐愛
One more chance 記憶に足を取られて
One more chance 被記憶絆住
One more chance 次の場所を選べない
One more chance 無法選擇下一個地方

いつでも捜しているよ どっかに君の姿を
無論何時都在尋找 希望能在某處找到妳
向いのホーム 路地裏の窓
對面的月台 小巷的窗戶裡
こんなとこにいるはずもないのに
明明知道妳不可能會在這裡
願いがもしも叶うなら 今すぐ君のもとへ
如果願望能夠實現 我希望馬上到妳身邊
できないことは もうなにもない
如今沒有我辦不到的事
すべてかけて抱きしめてみせるよ
我會賭上一切緊緊擁抱妳

寂しさ紛らすだけなら
如果只是為了排遣寂寞
誰でもいいはずなのに
應該不管是誰都無所謂
星が落ちそうな夜だから
但是在星辰要落下的夜晚
自分をいつわれない
我無法對自己說謊
One more time 季節よ うつろわないで
One more time 季節啊 希望你別轉變
One more time ふざけあった時間よ
One more time 與妳嬉鬧的時光啊

いつでも捜しているよ どっかに君の姿を
無論何時都在尋找 希望能在某處找到妳
交差点でも 夢の中でも
就算在路口 在算在夢中
こんなとこにいるはずもないのに
明知道妳不可能會在這裡
奇跡がもしも起こるなら 今すぐ君に見せたい
如果奇蹟會發生的話 希望馬上能讓妳看到
新しい朝 これからの僕
全新的早晨 從今以後的我
言えなかった「好き」という言葉も
還有過去說不出口的「喜歡妳」

夏の想い出がまわる ふいに消えた鼓動
夏日的回憶在腦中盤旋 突然消失的悸動

いつでも捜しているよ どっかに君の姿を
無論何時都在尋找 希望能在某處找到妳
明け方の街 桜木町で
在黎明的街頭 櫻木町
こんなとこに来るはずもないのに
明明知道妳不可能會來這裡
願いがもしも叶うなら 今すぐ君のもとへ
如果願望能夠實現 我希望馬上到妳身邊
できないことはもう何もない
如今沒有我辦不到的事
すべてかけて抱きしめてみせるよ
我會賭上一切緊緊擁抱妳

いつでも捜しているよ
無論何時都在尋找
どっかに君の破片を
希望在某處找到妳的線索
旅先の店 新聞の隅
旅途上的小店 新聞的角落
こんなとこにあるはずもないのに
明明知道妳根本不可能會出現
奇跡がもしも起こるなら 今すぐ君に見せたい
如果奇蹟會發生的話 希望馬上能讓妳看到
新しい朝 これからの僕
全新的早晨 從今以後的我
言えなかった「好き」という言葉も
還有過去說不出口的「喜歡妳」

いつでも捜してしまう どっかに君の笑顔を
無論何時都在尋找 希望在某處找到妳的笑容
急行待ちの 踏切あたり
在等待快車通過的 平交道
こんなとこにいるはずもないのに
明知道妳不可能會在這裡
命が繰り返すならば 何度も君のもとへ
如果生命能夠重來 無論幾次我都要到妳身邊
欲しいものなど もう何もない
現在我已經 別無所求
君のほかに大切なものなど
除了妳以外我什麼都不想要

2013年9月13日 星期五

2013年9月12日 星期四

【工具】線上小工具

紀錄一下 線上小工具


=============================================================
2016/01/01新增

2013年9月9日 星期一

【研究】YTB Downloader

前言

原本想推薦有一款不錯的youtube downloader HD,前幾年還不錯用,但最近幾乎每天都改版,一啟動就要你去更新,更新後不免又是安裝程式,裡面還包的不只有一種程式,虧他網頁還標榜沒有廣告、間諜...程式,結果一開始要安裝的Delta工具列,就是一個會自動綁你的IE、FireFox、Chrome、的惡意程式,真的大失所望。

每天更新,結果中文解碼又沒處理好,不知道再更新什麼,還是只是用自動化程式去跑,每天自動更新版本號和日期,讓google search時,資料是最新的,讓無知的使用者安裝有的沒的。
市面上越來越多號稱Free的軟體,都會綁一些怪怪的工具,甚至會修改機碼,讓你移除都無法,所在安裝時要注意看看到底是安裝了什麼內容到你的電腦裡。

不想用上述的幾乎每次啟動都要更新的下載器,其實還有許多選擇,譬如像是
  • chrome plug-in,若是每天都會用到youtub並下載,是很不錯。但是,plug-in是當打開chrome又會常駐在你電腦記憶體中,即使沒有瀏覽youtube畫面,plug-in一樣會存在在背景程式中。如果像我安裝了這些【工具】附加元件,多安裝一個不常用到的plug-in,白白耗費記憶體,很不划算。
  • Kej's FLV Retriever,網頁下載器,輸入網址後,需要先下載一個文件,再將文件的內容用記事本打開,貼到指定位置,最後才告知下載連結位置。等於下載動作需做兩次,對使用者來說太麻煩了。甚至,有時網址輸入錯誤,沒辦法即時得知錯誤訊息,需再貼上下載文件的內容後才得知輸入有誤,沒有一個很好的使用者經驗。

在上面實際做法後,參考他們處理方式,均是從youtube api取得youtube info的資訊,再從複雜的字串和數字的編碼,找出實際連結的位置,
舉例來說:
  • 原影片網址:http://www.youtube.com/watch?v=5y_KJAg8bHI
  • 把原網址改成http://www.youtube.com/get_video_info?video_id=5y_KJAg8bHI,就可以去取得所謂的youtube Info資訊,再分析這些資訊進一步取得實際影音的網址聯結。
按照wikipedia的說法,這些資訊包含了這些資訊,而影音格式也分為FLV、3GP(實際上info資訊裡是顯示3GPP)、MP4和WebM,而影片解析度則依上傳者的分享決定的,最高有到1080P,也就是前言那套軟體所說提供的HD畫值。

綜合以上知識,如果可以實作一套結合自動讀取info資訊檔,並分析info資料取得影片檔案實際下載位置,並download,就可以解決前面所有疑慮的問題。不需要耗費瀏覽器額外記憶體,不需要擔心首頁被綁架,不需要下載複製貼上才能下載。所以寫了一套YTB下載器,減少使用上的效率,但要遵守YOUTUBE 服務條款

以下程式碼僅供研究所用,無任何販售行為及獲得任何利益;若下載一切影音、文字,版權屬於原作者及出版社所有,請勿作商業上之用途,所有影音文字內容,請於實驗完後24小時以內將檔案刪除!
  • 這是ㄧ個自己研究用的下載器,裡面分析INFO資訊的演算法,則是參考Kej's FLV Retriever的處理方式。
  • 像是特定有授權的網站,用原始方式取得INFO資訊,會回傳沒有授權無法取得info的狀態,但是在後面加上eurl=.....後,又可以,但是實在查不出來eurl這個tag有什麼用意。
    • 例如:http://www.youtube.com/get_video_info?video_id=5y_KJAg8bHI&eurl=www.bbb.cc.dd
  • 設隱私的頁面仍然無法取得info。
  • 幾個類似的網址,可做處理:
    • http://www.youtube.com/watch?v=5y_KJAg8bHI
    • http://youtu.be/5y_KJAg8bHI
    • http://www.youtube.com/v/5y_KJAg8bHI 但會抓不到檔案名稱。

合體

其實這個下載器aCrawler只有console版的,須到config.properties中,更改設定,此外還包含了考古題下載器,所以整個程式碼,看起來會又臭又長。若網址輸入正確,目前可以下載郵局、銀行、和中華電信。但這部分考古題下載器的演算法還需要再改一下。

2013年9月5日 星期四

【GitHub】git did not exit cleanly (exit code 1)

git.exe push --all --progress  "origin"

To git@github.com:Ptodue/aCrawler.git
! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'git@github.com:Ptodue/aCrawler.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first merge the remote changes (e.g.,
hint: 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

就是說當GitHub有做修改時,要先push新資料到本機端,之後才能再pull上去。


2013年9月4日 星期三

【轉載】替JRE檔進行瘦身,降低包裝成EXE檔案大小

參考資料:http://simplecestlavie.blogspot.tw/2013/01/jre.html

【工具】將Java打包成EXE檔 - exe4j

使用工具:http://www.ej-technologies.com/products/exe4j/overview.html  exe4j
使用說明:http://www.blogjava.net/huliqing/archive/2008/04/18/193907.html
簡略步驟
1.先將檔案 export成 jar檔。
2.把用到的lib加進去設定。
3.設定產生的exe檔案名稱、產生位置、是以GUI或console或web service呈現。
4.設定程式執行的起始點(類別)。
5.設定JRE環境。(重要)
6.....設定版本號、軟體描述、icon...之類的。

【Java】使用者設定檔路徑(User Shell Folder)

有了這個就可以輕鬆取得使用者相關資料夾的相對路徑,不用因為設了絕對路徑,換一台電腦操作,因為使用者名稱不同,導致檔案路徑不同,造成找不到檔案的窘境。

【轉載】監控某個資料夾內檔案是否變動

ptt上看到, 也去找了相關的解決辦法。


工作上需要,要寫個程式,指定某個資料夾後, 便能監看資料夾(包含子資料夾)裡所有檔案,如果有發生新增、刪除、重新命名、重新被 寫入,就列出來。

解決辦法:
.Net Framework

Java
C++ (Native Code)


Qt
  • FileSystemWatcher類別
Linux(kernal version 2.6 up)
  • inotify()

2013年9月2日 星期一

【Eclipse】快捷鍵(Hot Key)



  • 快捷鍵:
    • F3  看class
    • Ctrl + L  移到指定行
    • Ctrl + F
    • Ctrl + H  File Search
    • Alt + /   show template proposals
    • Ctrl + /  註解
    • Ctrl + Shift + F  排版
      1. Window > Preference > Java > CodyStyle > Formatter
      2. 沿用舊Profile建立一個新的Profile,並且按下Edit。
      3. 切Line Wrapping頁面,把Maximum line width調整成適合的長度,就可以不面臨被斷行的程式碼。
    • Ctrl + Shift + O  載入切缺的import
    • Ctrl + 3  搜尋在分頁中的檔案
    • Ctrl + K 快速搜尋選取的字
    • Ctrl + Alt + H  顯示繼承架構
    • F11 快速執行(Debug模式)
      • F8  Resume
      • F5  Step into
      • F6  Step over
    • Alt + Shift + J 加入Java doc說明
    • Alt + Shift + R refactor (rename)
    • Ctrl + O 快速outline
    • Ctrl + E 快速轉換編輯器
    • Ctrl + M 當下編輯文件視窗最大化
    • Ctrl + Q 回到最後一次編輯的地方

  • 安裝Eclipse Plugin
    1. Help > Install New Software  (ex.中日文套件:properties Editor)
    2. Windows > Deferences > Install/Update > Available Software > Available Software Site
  • Auto Completion - 就像是c#中,隨便輸入任意字母,就會出現一個浮動的輔助小視窗,讓coder可以挑選函式、參數。可以eclipse預設下沒有這個功能,須透過設定...
    1. Window > Preference > Java > Editor > Content Assist
    2. 在triggers for Java欄位,預設是.,將此欄位改成.abcdefghijklmnopqrstuvwxyz ,> Apply。
      就類似Alt + /的功能,是不是很方便的說。